常见的BeanPostProcessor
前文我们简单讲了Bean的生命周期,以及生命周期的前后,本文将解释生命周期中的一些注解是怎么生效。
一、入门Demo
先准备了几个简单的类:
Bean01、Bean02什么都没有
public class Bean01 {
public Bean01() {
System.out.println("Bean01实例化~~~~~");
}
}
public class Bean02 {
public Bean02() {
System.out.println("Bean02被实例化~~");
}
}
Bean03将Bean01、Bean02分别通过@Autowired
和@Resource
注入,为了测试@Value
时能打印日志,因此使用了这种方式注入,上篇文章有同样的用法,这边不再解释。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
public class Bean03 {
private Bean01 bean01;
private Bean02 bean02;
private String home;
public Bean03() {
System.out.println("Bean03被实例化~~~~");
}
@Autowired
private void setBean01(Bean01 bean01) {
this.bean01 = bean01;
System.out.println("@autowired生效~~~~" + bean01);
}
@Resource
private void setBean02(Bean02 bean02) {
this.bean02 = bean02;
System.out.println("@Resource生效~~~" + bean02);
}
@Autowired
private void setHome(@Value("${JAVA_HOME}") String home) {
this.home = home;
System.out.println("@Value生效" + home);
}
@PostConstruct
public void init() {
System.out.println("@PostConstruct生效~~~~~");
}
@PreDestroy
public void destroy() {
System.out.println("@PreDestroy生效~~~~~");
}
}
最后是入口方法的代码:
import com.linqibin.spring.component.Bean01;
import com.linqibin.spring.component.Bean02;
import com.linqibin.spring.component.Bean03;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.context.support.GenericApplicationContext;
/**
* 测试往容器中添加一些Bean后置处理器时的作用
*
* @Date 2023/8/22 21:51
*/
public class TestProcessors {
public static void main(String[] args) {
// 通用ApplicationContext,这是一个比较【干净】的容器,可以用来测试手动添加后置处理器的效果
GenericApplicationContext context = new GenericApplicationContext();
// 往容器中添加三个Bean,默认是单例的,其中Bean03比较复杂,Bean01、Bean02中什么也没有
context.registerBean("bean01", Bean01.class);
context.registerBean("bean02", Bean02.class);
context.registerBean("bean03", Bean03.class);
// 初始化容器(也就是让ApplicationContext帮我们去执行BeanFactory的一系列流程)
context.refresh();
// 关闭容器
context.close();
}
}
这边我们使用的是GenericApplicationContext
,因为这个容器比较干净,其他的容器里面默认添加了一些BeanPostProcessor,不方便我们测试。执行main()
:
Bean03里面我们不是添加了很多东西吗?为什么就构造方法被执行了?
二、添加BeanPostProcessor
Spring在创建Bean的时候是通过各种Bean的后置处理器去管理Bean的生命周期,因此里面的各种依赖注入、初始化方法执行、销毁方法执行都是通过BeanPostProcessor
生效的。
1. AutowiredAnnotationBeanPostProcessor
根据名字我们就能看出来,这个后置处理器的作用就是来处理@Autowired
的,我们将他添加进main()
:
public static void main(String[] args) {
// 通用ApplicationContext,这是一个比较【干净】的容器,可以用来测试手动添加后置处理器的效果
GenericApplicationContext context = new GenericApplicationContext();
// 往容器中添加三个Bean,默认是单例的,其中Bean03比较复杂,Bean01、Bean02中什么也没有
context.registerBean("bean01", Bean01.class);
context.registerBean("bean02", Bean02.class);
context.registerBean("bean03", Bean03.class);
// >>>>>>>>>添加BeanPostProcessor<<<<<<<<<<
// 因为涉及到注入String对象,所以需要换掉候选解析器(先看个眼熟,后续讲)
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// 添加后,@Autowired、@Value会生效
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
// 初始化容器(也就是让ApplicationContext帮我们去执行BeanFactory的一系列流程)
context.refresh();
context.close();
}
因为涉及到注入String——Bean03的setHome()
,所以需要换掉候选解析器(混个眼熟,后续讲)。
可以看到,Bean03实例化后,@Value
和@Autowired
都生效了,都成功注入属性了。
2. CommonAnnotationBeanPostProcessor
这个后置处理器是添加javax包下的一些注解的处理,如@Resource
,@PostConstruct
,@PreDestroy
。
// 添加后,@Resource、@PostConstruct、@PreDestroy会生效
context.registerBean(CommonAnnotationBeanPostProcessor.class);
可以看到,这三个注解生效了。
3. ConfigurationPropertiesBindingPostProcessor
这个处理器是SpringBoot才有的,用来处理@ConfigurationProperties
。
先添加Bean04,是一个配置属性类(因为java.home,java.version环境变量中有,因此不需要额外添加):
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 测试ConfigurationProperties
*
* @Author linqibin
* @Date 2023/8/22 23:14
* @Email 1214219989@qq.com
*/
@Data
@ConfigurationProperties(prefix = "java")
public class Bean04 {
private String home;
private String version;
}
在main()
中添加bean04
,然后刷新容器,并打印bean04:
// 添加后,@ConfigurationProperties会生效
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
context.registerBean("bean04", Bean04.class);
// 初始化容器(也就是让ApplicationContext帮我们去执行BeanFactory的一系列流程)
context.refresh();
System.out.println(context.getBean("bean04"));