【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
这个参考博文:Spring中Bean注入与获取几种方式详解
【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;
}
}