【1】@Value和@PropertySource
① @Value
该注解可以直接给bean的属性赋值(不支持JSR303校验),具体有以下几种用法:
- 基本数值
- 可以写SpEL;
#{}
- 可以写
${}
;取出配置文件【properties】中的值(在运行环境变量里面的值)
Bean类如下:
public class Person { @Value("张三") private String name; @Value("#{20-2}") private Integer age; @Value("${person.nickName}") private String nickName; //... }
注意到,nickName属性使用了配置文件中的值,那么如何引入配置文件呢?
② @PropertySource
该注解读取外部配置文件中的k/v保存到运行的环境变量中,加载完外部的配置文件以后使用${}取出配置文件的值。
注解接口如下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Repeatable(PropertySources.class) public @interface PropertySource { // 声明资源文件名字 String name() default ""; // 声明需要加在的资源文件位置,例如classpath:/com/myco/app.properties // 或者 file:/path/to/file,不支持通配符,必须是确切的文件路径 // 可以使用${...} String[] value(); // 声明如果查找资源文件失败,是否忽略 // 如果资源文件是可选的,那么建议设置为true // 默认是false boolean ignoreResourceNotFound() default false; // 资源文件字符编码,如"UTF-8" String encoding() default ""; // 指定一个自定义的PropertySourceFactory Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class; }
配置类如下:
@PropertySource(value={"classpath:/person.properties"}) @Configuration public class MainConfigOfPropertyValues { @Bean public Person person(){ return new Person(); } }
测试如下:
public class IOCTest_PropertyValue { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class); @Test public void test01(){ printBeans(applicationContext); System.out.println("============="); Person person = (Person) applicationContext.getBean("person"); System.out.println(person); //配置文件中的值存在于环境中,可以使用如下方式获取 ConfigurableEnvironment environment = applicationContext.getEnvironment(); String property = environment.getProperty("person.nickName"); System.out.println(property); applicationContext.close(); } private void printBeans(AnnotationConfigApplicationContext applicationContext){ String[] definitionNames = applicationContext.getBeanDefinitionNames(); for (String name : definitionNames) { System.out.println(name); } } }
测试结果如下:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfigOfPropertyValues person ============= Person [name=张三, age=18, nickName=小李四] 小李四
从Properties文件中取值得三种方式:
@PropertySource("classpath:/dbconfig.properties") @Configuration public class MainConfigOfProfile implements EmbeddedValueResolverAware{ @Value("${db.user}")//第一种,成员属性 @Value private String user; private StringValueResolver valueResolver; private String driverClass; @Bean public Yellow yellow(){ return new Yellow(); } // 第二种,参数 @Value @Profile("test") @Bean("testDataSource") public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws Exception{ // 第二种,参数 @Value ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser(user); dataSource.setPassword(pwd); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); dataSource.setDriverClass(driverClass); return dataSource; } // 第三种,使用值解析器,从环境中获取值。 @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { // TODO Auto-generated method stub this.valueResolver = resolver; driverClass = valueResolver.resolveStringValue("${db.driverClass}"); } }
【2】@Autowired @Resource 和 @Inject
【3】实现XxxAware接口,将Spring底层组件注入bean
自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx)。
自定义组件实现xxxAware接口,在创建对象的时候,会调用接口规定的方法注入相关组件。
每一个xxxAware都有一个对应的xxxProcessor后置处理器来实现其功能。
ApplicationContextAware==》ApplicationContextAwareProcessor;
自定义bean类如下:
@Component public class Red implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("传入的ioc:"+applicationContext); this.applicationContext = applicationContext; } @Override public void setBeanName(String name) { System.out.println("当前bean的名字:"+name); } @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { String resolveStringValue = resolver.resolveStringValue("你好 ${os.name} 我是 #{20*18}"); System.out.println("解析的字符串:"+resolveStringValue); } }
测试如下:
当前bean的名字:red 解析的字符串:你好 Windows 7 我是 360 传入的ioc:org.springframework.context.annotation.AnnotationConfigApplicationContext@11028347: startup date [Tue Apr 10 11:09:18 CST 2018]; root of context hierarchy
后置处理器实现源码:
ApplicationContextAwareProcessor 是一个bean后置处理器实现类,将ApplicationContext 传递给那些实现了EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware及ApplicationContextAware接口的bean。
被实现的接口按照上述顺序得到满足。应用程序上下文将自动向其基础bean工厂注册。应用程序不直接使用它。
这个过程可以参考AbstractApplicationContext#refresh()的方法。
class ApplicationContextAwareProcessor implements BeanPostProcessor { private final ConfigurableApplicationContext applicationContext; private final StringValueResolver embeddedValueResolver; // 创建一个ApplicationContextAwareProcessor public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) { this.applicationContext = applicationContext; this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory()); } @Override public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException { AccessControlContext acc = null; if (System.getSecurityManager() != null && (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) { acc = this.applicationContext.getBeanFactory().getAccessControlContext(); } if (acc != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { invokeAwareInterfaces(bean); return null; } }, acc); } else { // 核心方法 invokeAwareInterfaces(bean); } return bean; } // 判断bean的类型,然后传递applicationContext private void invokeAwareInterfaces(Object bean) { if (bean instanceof Aware) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); } } } @Override public Object postProcessAfterInitialization(Object bean, String beanName) { return bean; } }