内容概要:
- Bean 后处理器的作用:为 Bean 生命周期各个阶段提供扩展
- 在beanFactory中补充一些Bean的定义,用于解析 @Autowired @Resource @Value @ConfigurationProperties…
- 常见的Bean后处理器
- AutowiredAnnotationBeanPostProcessor : 用于解析 @Autowired @Value 注解
- CommonAnnotationBeanPostProcessor : 用于解析@Resource @PostConstruct @PreDestroy 注解
- ConfigurationPropertiesBindingPostProcessor : Spring Boot中的,用于解析 @ConfigurationProperties 注解,该注解用于将指定前缀的配置进行属性绑定
${}
、#{}
GenericApplicationContext
容器来进行测试验证
GenericApplicationContext
是一个【干净】的ApplicationContext容器context.registerBean(beanName, beanClass)
: 向 ApplicationContext 里注册Bean
context.refresh()
: 初始化容器
context.close()
: 销毁容器
AutowireCandidateResolver
不会解析@Value, ContextAnnotationAutowireCandidateResolver
可以用来获取@Value中值${}
、#{}
AutowiredAnnotationBeanPostProcessor
: 用于解析 @Autowired @Value 注解CommonAnnotationBeanPostProcessor
: 用于解析@Resource @PostConstruct @PreDestroy 注解
@Slf4j
static class Bean1 {
private Bean2 bean2;
@Autowired
public void setBean2(Bean2 bean2) {
log.debug("@Autowired 生效: {}", bean2);
this.bean2 = bean2;
}
private Bean3 bean3;
@Resource
public void setBean3(Bean3 bean3) {
log.debug("@Resource 生效: {}", bean3);
this.bean3 = bean3;
}
private String home;
@Autowired
public void setHome(@Value("${JAVA_HOME}") String home) {
log.debug("@Value 生效: {}", home);
this.home = home;
}
public Bean1() {
log.debug("构造 生效");
}
@PostConstruct
public void init() {
log.debug("@PostConstruct 生效");
}
@PreDestroy
public void destroy() {
log.debug("@PreDestroy 生效");
}
}
@Slf4j
static class Bean2 {
public Bean2() {
log.debug("构造 生效");
}
}
@Slf4j
static class Bean3 {
public Bean3() {
log.debug("构造 生效");
}
}
public static void main() {
// GenericApplicationContext 是一个【干净】的容器,没有添加额外的BeanFactory后处理器、Bean后处理器,方便测试
GenericApplicationContext context = new GenericApplicationContext();
// 用原始方法注册三个bean
context.registerBean("bean1", Bean1.class);
context.registerBean("bean2", Bean2.class);
context.registerBean("bean3", Bean3.class);
// BeanFactory不会主动调用Bean后处理器(用于解析@Autowired、@Resource..)(BeanFactory的特点之二)
// BeanFactory不会解析 `${}`、`#{}`(BeanFactory的特点之三)
// 获取@Value的值
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// 向BeanFactory中添加解析${} 的解析器
context.getDefaultListableBeanFactory().addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders); // 解析 ${}
// 注册Bean后处理器,这个后处理器用于解析@Autowired @Value注解
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
// 注册Bean后处理器,这个后处理器用于解析@Resource @PostConstruct @PreDestroy注解
context.registerBean(CommonAnnotationBeanPostProcessor.class); // 虽然注册在后面,但是会先解析@Resource 再解析@Autowired
// 初始化容器: 用于初始化所有单例,执行BeanFactory后处理器和Bean后处理器
// 在初始化容器前 Bean 和 Bean后处理器只是注册到Bean,并不会实例化对象
context.refresh();
// 销毁容器
context.close();
}
输出
15:09:15.041 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@156643d4
15:09:15.063 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor'
15:09:15.081 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.CommonAnnotationBeanPostProcessor'
15:09:15.089 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
15:09:15.110 [main] DEBUG com.xxx.TestApplication$Bean1 - 构造 生效
15:09:15.158 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean3'
15:09:15.158 [main] DEBUG com.xxx.TestApplication$Bean3 - 构造 生效
15:09:15.159 [main] DEBUG com.xxx.TestApplication$Bean1 - @Resource 生效: com.huat.lisa.studyspring.s04.S04Application$Bean3@25af5db5
15:09:15.164 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'JAVA_HOME' in PropertySource 'systemEnvironment' with value of type String
15:09:15.172 [main] DEBUG com.xxx.TestApplication$Bean1 - @Value 生效: /Library/Java/JavaVirtualMachines/jdk1.8.0_261.jdk/Contents/Home/
15:09:15.174 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
15:09:15.174 [main] DEBUG com.xxx.TestApplication$Bean2 - 构造 生效
15:09:15.175 [main] DEBUG com.xxx.TestApplication$Bean1 - @Autowired 生效: com.huat.lisa.studyspring.s04.S04Application$Bean2@a74868d
15:09:15.175 [main] DEBUG com.xxx.TestApplication$Bean1 - @PostConstruct 生效
Process finished with exit code 0
Spring Boot 中的后处理器
@ConfigurationProperties
注解可以进行属性绑定,用于将指定前缀的属性绑定到实体上
postProcessBeforeInitialization()
方法内解析ConfigurationPropertiesBindingPostProcessor
: 用于解析 @ConfigurationProperties 注解··@ConfigurationProperties(prefix = "java")
static class Bean4 {
// java.version
private String version;
// java.home
private String home;
public String getHome() {
return home;
}
public void setHome(String home) {
this.home = home;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
@Override
public String toString() {
return "Bean4{" +
"version='" + version + '\'' +
", home='" + home + '\'' +
'}';
}
}
public static void testConfigurationPropertiesBindingPostProcessor() {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean4", Bean4.class);
// ConfigurationPropertiesBindingPostProcessor 用于属性绑定后处理器, 解析
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
context.refresh();
System.out.println(context.getBean(Bean4.class));
context.close();
}
AutowiredAnnotationBeanPostProcessor
解析 @Autiwired @Value 注解时,核心方法为 postProcessProperties()
public static void testAutowiredAnnotationBeanPostProcessor() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("bean2", new Bean2()); // 注册一个实例化完成的Bean到BeanFactory,这种方式注册会跳过Bean的创建过程、依赖注入、初始化
beanFactory.registerSingleton("bean3", new Bean3());
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); // 解析@Value
beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders); // 解析 ${}
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1();
System.out.println(bean1); // 此时 @Autowired @Value 都没有注入,输出成员变量都为null
// 执行依赖注入 @Autowired @Value
// 第一个参数PropertyValues组装需要注入的值,非空时,则直接从PropertyValues里获取自动注入的值,不会从BeanFactory里获取
processor.postProcessProperties(null, bean1, "bean1");
System.out.println(bean1); // @Autowired @Value 注入成功
}
postProcessProperties()
方法源码@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 查找当前类中哪些属性/方法使用了 @Autowired @Value 注解,将对应属性和方法信息 存储到 InjectionMetadata 的 injectedElements 成员变量中
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// InjectionMetadata通过反射的方式,设置对应的属性/set方法,进行依赖注入
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
findAutowiringMetadata()
和 metadata.inject()
方法public static void testFindAutowiringMetadata() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("bean2", new Bean2()); // 注册一个实例化完成的Bean到BeanFactory,这种方式注册会跳过Bean的创建过程、依赖注入、初始化
beanFactory.registerSingleton("bean3", new Bean3());
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); // 解析@Value
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
processor.setBeanFactory(beanFactory);
Bean1 bean1 = new Bean1();
// 通过反射方式调用 processor.findAutowiringMetadata()
Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
findAutowiringMetadata.setAccessible(true);
// 获取bean1 上加了 @Autowired @Value 注解的 成员变量/成员方法 信息,存储到 InjectionMetadata 的 injectedElements 成员变量中
InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor, "bean1", Bean1.class, null);
// 可以通过debug方法看到 metadata里的 injectedElements 成员变量,有两个值,分别是 setBean2 和 setHome
System.out.println(metadata);
// 调用 InjectionMetadata 来进行依赖注入,注入时按类型查找信息
metadata.inject(bean1, "bean1", null);
System.out.println(bean1);// @Autowired @Value 成功注入
}
metadata.inject()
方法的核心实现
beanFactory.doResolveDependency()
方法,从BeanFactory中根据类型找到对应的Beanpublic static void injectByField() throws NoSuchFieldException, IllegalAccessException {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("bean3", new Bean3());
Field field = Bean1.class.getDeclaredField("bean3");
// 将待依赖的成员变量/方法信息 封装成 DependencyDescriptor
DependencyDescriptor desc = new DependencyDescriptor(field, true);
// 根据成员变量按类型去找要注入哪个Bean, 后面的三个变量都可以为null, 因为可以根据DependencyDescriptor找到要依赖的对象信息
Object obj = beanFactory.doResolveDependency(desc, null, null, null);
System.out.println(obj); // 打印bean3
// 通过反射,将bean3设置到Bean1里
Bean1 bean1 = new Bean1();
field.setAccessible(true);
field.set(bean1, obj);
System.out.println(obj); // 成功注入bean3
}
public static void injectByMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("bean2", new Bean2());
Method method = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
// 将待依赖注入的成员变量/方法信息 封装成 DependencyDescriptor
// MethodParameter 描述待依赖注入的方法及该方法中第几个变量需要依赖注入
DependencyDescriptor desc = new DependencyDescriptor(new MethodParameter(method, 0), true);
Object obj = beanFactory.doResolveDependency(desc, null, null, null);
System.out.println(obj);
// 通过反射,将bean2设置到Bean1里
Bean1 bean1 = new Bean1();
method.setAccessible(true);
method.invoke(bean1, obj);
System.out.println(bean1);// 成功注入bean2
}
public static void injectByValue(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); // 解析@Value
beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders); // 解析 ${}
Method method = Bean1.class.getDeclaredMethod("setHome", String.class);
// 将待依赖注入的成员变量/方法信息 封装成 DependencyDescriptor
// MethodParameter 描述待依赖注入的方法及该方法中第几个变量需要依赖注入
DependencyDescriptor desc = new DependencyDescriptor(new MethodParameter(method, 0), true);
Object obj = beanFactory.doResolveDependency(desc, null, null, null);
System.out.println(obj);
// 通过反射,将bean2设置到Bean1里
Bean1 bean1 = new Bean1();
method.setAccessible(true);
method.invoke(bean1, obj);
System.out.println(bean1);
}
static class Bean1 {
// 成员变量依赖注入
@Autowired
private Bean3 bean3;
public void setBean3(Bean3 bean3) {
this.bean3 = bean3;
}
private Bean2 bean2;
// set方法依赖注入
@Autowired
public void setBean2(Bean2 bean2) {
this.bean2 = bean2;
}
}