5.Spring5底层原理之Bean后处理器执行流程分析
常见的Bean后处理器
这章我们来看看常见的一些bean处理器,首先我们使用GenericApplicationContext,这个ApplicationContext是一个纯净的context,没有包含后处理器,方便我们后续观察。
先上代码
三个bean类
public class Bean1 {
private final static Logger log = LoggerFactory.getLogger(Bean1.class);
public Bean1(){
log.debug("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;
}
@PostConstruct
public void init(){
log.debug("@PostConstruct 生效");
}
@PreDestroy
public void destroy(){
log.debug("@PreDestroy 生效");
}
@Override
public String toString() {
return "Bean1{" +
"bean2=" + bean2 +
", bean3=" + bean3 +
", home='" + home + '\'' +
'}';
}
}
public class Bean2 {
private final static Logger log = LoggerFactory.getLogger(Bean2.class);
public Bean2(){
log.debug("bean2 构造");
}
}
public class Bean3 {
private final static Logger log = LoggerFactory.getLogger(Bean3.class);
public Bean3(){
log.debug("bean3 构造");
}
}
测试类
public class A04Application {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean1",Bean1.class);
context.registerBean("bean2",Bean2.class);
context.registerBean("bean3",Bean3.class);
context.refresh();
System.out.println(context.getBean(Bean1.class));
context.close();
}
}
现在我们来讲解一下这些代码,首先我们新建了3个bean,其中bean1比较关键,它用@Autowired注入bean2,用@Resource注入bean3,用@Autowired+@Value注入方法的String参数,并且还有@PostConstruct和@PreDestroy注解的使用,在这些关键的地方,我们都进行了日志输出。
在测试类中,我们注册了3个bean,其中context.refresh方法,用来刷新Spring上下文,做初始化操作,其中包含帮我们自动执行后处理器,现在我们还没有添加后处理器,添加以后会自动帮我们执行。然后获取bean1,观察输出结果。
我们知道这种情况Spring会帮我们创建这些bean的实例,但是由于GenericApplicationContext没有包含任何bean后处理器,所以类似@Autowired注解无法解析。我们运行一下程序来验证我们的想法。看看日志输出结果。
17:21:07.257 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@74a10858
17:21:07.319 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
17:21:07.335 [main] DEBUG com.zhaojun.springsource.a04.Bean1 - bean1 构造
17:21:07.336 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
17:21:07.336 [main] DEBUG com.zhaojun.springsource.a04.Bean2 - bean2 构造
17:21:07.336 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean3'
17:21:07.337 [main] DEBUG com.zhaojun.springsource.a04.Bean3 - bean3 构造
Bean1{bean2=null, bean3=null, home='null'}
17:21:07.397 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@74a10858, started on Thu Apr 21 17:21:07 CST 2022
通过日志我们可以看到,3个bean都已实例化完成,但是却没有为我们进行注入,所有注解都没用解析生效。
AutowiredAnnotationBeanPostProcessor
接下来我们看看第一个bean后处理器AutowiredAnnotationBeanPostProcessor,这个后处理器主要用来解析@Autowired注解,也可以解析@Value注解
public class A04Application {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean1",Bean1.class);
context.registerBean("bean2",Bean2.class);
context.registerBean("bean3",Bean3.class);
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); // 不加在取@Value注解值时会报错
context.registerBean(AutowiredAnnotationBeanPostProcessor.class); // @Autowired @Value
context.refresh();
System.out.println(context.getBean(Bean1.class));
context.close();
}
}
然后我们再看日志输出
17:27:17.814 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@28ac3dc3
17:27:17.862 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor'
17:27:17.899 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
17:27:17.929 [main] DEBUG com.zhaojun.springsource.a04.Bean1 - bean1 构造
17:27:18.088 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'JAVA_HOME' in PropertySource 'systemEnvironment' with value of type String
17:27:18.098 [main] DEBUG com.zhaojun.springsource.a04.Bean1 - @Value 生效:C:\Program Files\Java\jdk1.8.0_121
17:27:18.102 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
17:27:18.103 [main] DEBUG com.zhaojun.springsource.a04.Bean2 - bean2 构造
17:27:18.104 [main] DEBUG com.zhaojun.springsource.a04.Bean1 - @Autowired 生效:com.zhaojun.springsource.a04.Bean2@e1de817
17:27:18.104 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean3'
17:27:18.104 [main] DEBUG com.zhaojun.springsource.a04.Bean3 - bean3 构造
Bean1{bean2=com.zhaojun.springsource.a04.Bean2@e1de817, bean3=null, home='C:\Program Files\Java\jdk1.8.0_121'}
17:27:18.128 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@28ac3dc3, started on Thu Apr 21 17:27:17 CST 2022
其中bean2和home注入成功,@Autowired和@Value注解生效。
CommonAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor主要用来处理 @Resource @PostConstruct @PreDestroy 注解
public class A04Application {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean1",Bean1.class);
context.registerBean("bean2",Bean2.class);
context.registerBean("bean3",Bean3.class);
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); // 不加在取@Value注解值时会报错
context.registerBean(AutowiredAnnotationBeanPostProcessor.class); // @Autowired @Value
context.registerBean(CommonAnnotationBeanPostProcessor.class); // @Resource @PostConstruct @PreDestroy
context.refresh();
System.out.println(context.getBean(Bean1.class));
context.close();
}
}
日志输出
10:55:47.877 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@28ac3dc3
10:55:47.923 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor'
10:55:47.949 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.CommonAnnotationBeanPostProcessor'
10:55:47.960 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
10:55:47.984 [main] DEBUG com.zhaojun.springsource.a04.Bean1 - bean1 构造
10:55:48.098 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean3'
10:55:48.098 [main] DEBUG com.zhaojun.springsource.a04.Bean3 - bean3 构造
10:55:48.099 [main] DEBUG com.zhaojun.springsource.a04.Bean1 - @Autowired 生效:com.zhaojun.springsource.a04.Bean3@17a7f733
10:55:48.109 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
10:55:48.109 [main] DEBUG com.zhaojun.springsource.a04.Bean2 - bean2 构造
10:55:48.110 [main] DEBUG com.zhaojun.springsource.a04.Bean1 - @Autowired 生效:com.zhaojun.springsource.a04.Bean2@50caa560
10:55:48.116 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'JAVA_HOME' in PropertySource 'systemEnvironment' with value of type String
10:55:48.126 [main] DEBUG com.zhaojun.springsource.a04.Bean1 - @Value 生效:C:\Program Files\Java\jdk1.8.0_121
10:55:48.126 [main] DEBUG com.zhaojun.springsource.a04.Bean1 - @PostConstruct 生效
Bean1{bean2=com.zhaojun.springsource.a04.Bean2@50caa560, bean3=com.zhaojun.springsource.a04.Bean3@17a7f733, home='C:\Program Files\Java\jdk1.8.0_121'}
10:55:48.168 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@28ac3dc3, started on Fri Apr 22 10:55:47 CST 2022
10:55:48.170 [main] DEBUG com.zhaojun.springsource.a04.Bean1 - @PreDestroy 生效
ConfigurationPropertiesBindingPostProcessor
这个后处理器,用来处理@ConfigurationProperties,为此我们创建一个bean4,它来注入环境中java的版本信息
@ConfigurationProperties(prefix = "java")
public class Bean4 {
private final static Logger log = LoggerFactory.getLogger(Bean4.class);
private String home;
private String version;
public Bean4(){
log.debug("bean4 构造");
}
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{" +
"home='" + home + '\'' +
", version='" + version + '\'' +
'}';
}
}
测试类
public class A04Application {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("bean4",Bean4.class);
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory()); //@ConfigurationProperties
context.refresh();
System.out.println(context.getBean(Bean4.class));
context.close();
}
}
ConfigurationPropertiesBindingPostProcessor的使用方式与前面的不一样,我们运行看看结果
11:03:26.771 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@74a10858
11:03:26.805 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor'
11:03:26.823 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.boot.context.internalConfigurationPropertiesBinder'
11:03:26.824 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.boot.context.internalConfigurationPropertiesBinderFactory'
11:03:26.832 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean4'
11:03:26.834 [main] DEBUG com.zhaojun.springsource.a04.Bean4 - bean4 构造
Bean4{home='C:\Program Files\Java\jdk-11.0.11', version='11.0.11'}
11:03:27.047 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@74a10858, started on Fri Apr 22 11:03:26 CST 2022
常用的后处理器讲完后,我们来了解下后处理器的执行流程。
后处理器执行流程
这一节我们来了解下后处理器的大致执行流程,我们以AutowiredAnnotationBeanPostProcessor后处理器为例,后处理器执行处理的方法是postProcessProperties(),我们试试手动调用这个方法。
public class DigInAutowired {
public static void main(String[] args) throws Throwable {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("bean2", new Bean2());
beanFactory.registerSingleton("bean3", new Bean3());
// AbstractBeanDefinition bean3 = BeanDefinitionBuilder.genericBeanDefinition(Bean3.class).setScope("singleton").getBeanDefinition();
// beanFactory.registerBeanDefinition("bean3",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);
System.out.println("---");
// pvs 参数:自动装配的值 这里填null 根据类型去匹配
processor.postProcessProperties(null, bean1, "bean1"); //执行依赖注入 解析@Autowired @Value
System.out.println(bean1);
}
}
其中需要注意的是,在注册bean的时候,我们采用的直接new出来,这样spring会认为是一个完成的bean,就不会执行创建、依赖注入、初始化过程,其实bean2,bean3也不需要看到这些,简单起见就直接new来注册的bean,当然也可以采用注册bean定义的方法。注释中有示例。
我们进行手动调用postProcessProperties,观察打印日志
11:23:33.204 [main] DEBUG com.zhaojun.springsource.a04.Bean2 - bean2 构造
11:23:33.212 [main] DEBUG com.zhaojun.springsource.a04.Bean3 - bean3 构造
11:23:33.241 [main] DEBUG com.zhaojun.springsource.a04.Bean1 - bean1 构造
Bean1{bean2=null, bean3=null, home='null'}
---
11:23:33.411 [main] DEBUG com.zhaojun.springsource.a04.Bean1 - @Autowired 生效:com.zhaojun.springsource.a04.Bean2@41d477ed
11:23:33.423 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'JAVA_HOME' in PropertySource 'systemEnvironment' with value of type String
11:23:33.424 [main] DEBUG com.zhaojun.springsource.a04.Bean1 - @Value 生效:C:\Program Files\Java\jdk1.8.0_121
Bean1{bean2=com.zhaojun.springsource.a04.Bean2@41d477ed, bean3=null, home='C:\Program Files\Java\jdk1.8.0_121'}
日志中我们可以看到,没有执行postProcessProperties,没有给我们注入。执行后就注入成功了。
我们来看看postProcessProperties()的源码
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
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;
}
断点看看metadata是什么
metadata中有两个属性,一个是targetClass,就是目标类,就是bean1。另外一个属性是injectedElements,是一个集合,分别对应着@Autowired注解标注的位置,一个是bean2方法,一个是setHome方法。
接下来看看inject方法,inject方法其实就是获取到@Autowired注解的字段或方法,通过反射创建注入的bean实例。
注入的是字段
@Autowired
private Bean3 bean3;
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("bean3", new Bean3());
Field bean3 = Bean1.class.getDeclaredField("bean3");
DependencyDescriptor dd1 = new DependencyDescriptor(bean3,false);
Object o = beanFactory.doResolveDependency(dd1, null, null, null);
System.out.println(o);
输出结果
14:56:42.341 [main] DEBUG com.zhaojun.springsource.a04.Bean3 - bean3 构造
com.zhaojun.springsource.a04.Bean3@314c508a
注入的是方法
private Bean2 bean2;
@Autowired
public void setBean2(Bean2 bean2){
this.bean2 = bean2;
}
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("bean2", new Bean2());
Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(setBean2, 0), false);
Object o2 = beanFactory.doResolveDependency(dd2, null, null, null);
System.out.println(o2);
输出结果
15:07:35.252 [main] DEBUG com.zhaojun.springsource.a04.Bean2 - bean2 构造
com.zhaojun.springsource.a04.Bean2@59717824
值注入方法
private String home;
@Autowired
public void setHome(@Value("${JAVA_HOME}")String home){
this.home = home;
}
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); //@Value
beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders); // 解析${}
Method setHome = Bean1.class.getDeclaredMethod("setHome", String.class);
DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(setHome, 0), false);
Object o3 = beanFactory.doResolveDependency(dd3, null, null, null);
System.out.println(o3);
输出结果
15:13:13.470 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'JAVA_HOME' in PropertySource 'systemEnvironment' with value of type String
C:\Program Files\Java\jdk1.8.0_121