9.Spring底层原理之Aware和InitializingBean接口,后处理器失效
这一节主要了解Aware接口和InitializingBean接口的作用,常见的Aware接口有:BeanNameAware、BeanFactoryAware、ApplicationContextAware等
Aware接口和InitializingBean的作用
他们的作用如下:
- BeanNameAware 注入bean的名字
- BeanFactoryAware 注入beanFactory
- ApplicationContextAware 注入ApplicationContext
- EmbeddedValueResolverAware 解析${}
- InitializingBean 初始化方法
举例实现
举个例子
public class MyBean implements BeanNameAware, ApplicationContextAware, BeanFactoryAware, InitializingBean {
public static final Logger log = LoggerFactory.getLogger(MyBean.class);
@Override
public void setBeanName(String name) {
log.debug("{},beanName:{}",this,name);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.debug("applicationContext:{}",applicationContext);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
log.debug("beanFactory:{}",beanFactory);
}
@Override
public void afterPropertiesSet() throws Exception {
log.debug("可以进行一些初始化操作");
}
}
MyBean 分别实现BeanNameAware, ApplicationContextAware, BeanFactoryAware, InitializingBean接口。
public class A06Application {
public static final Logger log = LoggerFactory.getLogger(A06Application.class);
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("myBean",MyBean.class);
context.refresh();
context.close();
}
}
执行日志
11:11:58.372 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@42607a4f
11:11:58.458 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myBean'
11:11:58.484 [main] DEBUG com.zhaojun.springsource.a06.MyBean - com.zhaojun.springsource.a06.MyBean@5ae50ce6,beanName:myBean
11:11:58.485 [main] DEBUG com.zhaojun.springsource.a06.MyBean - beanFactory:org.springframework.beans.factory.support.DefaultListableBeanFactory@49d904ec: defining beans [myBean]; root of factory hierarchy
11:11:58.485 [main] DEBUG com.zhaojun.springsource.a06.MyBean - applicationContext:org.springframework.context.support.GenericApplicationContext@42607a4f, started on Mon May 23 11:11:58 CST 2022
11:11:58.490 [main] DEBUG com.zhaojun.springsource.a06.MyBean - 可以进行一些初始化操作
11:11:58.520 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@42607a4f, started on Mon May 23 11:11:58 CST 2022
可以看到,实现的方法都注入成功了。
我们可能会想到,@Autowired和@PostConstruct也可以达到同样的目的呀,为什么还需要这些接口呢。
@Autowired 的解析需要用到bean后处理器,属于扩展功能,而Aware接口属于内置功能,不用添加任何扩展。扩展在某些情况下会失效,但是内置功能不会失效。因此 Spring 框架内部的类常用它们进行注入。
后处理器失效的情况
我们来看看一种后处理器失效的情况
@Configuration
public class MyConfig {
public static final Logger log = LoggerFactory.getLogger(MyConfig.class);
@Autowired
public void setApplicationContext(ApplicationContext applicationContext){
log.debug("注入applicationContext");
}
@PostConstruct
public void init(){
log.debug("初始化");
}
}
public class A06Application {
public static final Logger log = LoggerFactory.getLogger(A06Application.class);
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("myConfig",MyConfig.class);
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
context.registerBean(CommonAnnotationBeanPostProcessor.class);
context.registerBean(ConfigurationClassPostProcessor.class);
context.refresh();
context.close();
}
}
我们创建了MyConfig配置类,用@Autowired注入了ApplicationContext,用@PostConstruct进行初始化。在main方法中,添加后处理器,保证注解都能够正常解析。来看看日志
11:19:41.611 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@42607a4f
11:19:41.641 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.ConfigurationClassPostProcessor'
11:19:41.786 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor'
11:19:41.789 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.CommonAnnotationBeanPostProcessor'
11:19:41.796 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myConfig'
11:19:41.876 [main] DEBUG com.zhaojun.springsource.a06.MyConfig - 注入applicationContext
11:19:41.876 [main] DEBUG com.zhaojun.springsource.a06.MyConfig - 初始化
11:19:41.888 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@42607a4f, started on Mon May 23 11:19:41 CST 2022
可以看到,@Autowired和@PostConstruct都生效了。现在我们在MyConfig类中再加一个方法。
@Configuration
public class MyConfig {
public static final Logger log = LoggerFactory.getLogger(MyConfig.class);
@Autowired
public void setApplicationContext(ApplicationContext applicationContext){
log.debug("注入applicationContext");
}
@PostConstruct
public void init(){
log.debug("初始化");
}
@Bean
public BeanFactoryPostProcessor processor(){
return beanFactory -> {
log.debug("执行 processor");
};
}
}
我们新增了一个processor()方法,这个方法是注册了一个BeanFactoryPostProcessor后处理器。
然后我们再执行,查看日志
11:22:24.643 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@42607a4f
11:22:24.668 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.ConfigurationClassPostProcessor'
11:22:24.822 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'processor'
11:22:24.822 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myConfig'
11:22:24.829 [main] INFO org.springframework.context.annotation.ConfigurationClassEnhancer - @Bean method MyConfig.processor is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean javadoc for complete details.
11:22:24.837 [main] DEBUG com.zhaojun.springsource.a06.MyConfig - 执行 processor
11:22:24.838 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor'
11:22:24.840 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.CommonAnnotationBeanPostProcessor'
11:22:24.876 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@42607a4f, started on Mon May 23 11:22:24 CST 2022
可以看到processor()方法执行了,但是之前的两个方法都没有执行。这是怎么回事呢。我们看看下面的时序图。
正常情况下,是先执行BeanFactory后处理器,然后再进行实例化,但是当配置类包含BeanFactoryPostProcessor时,要创建BeanFactoryPostProcessor必须先实例化,此时的bean后处理器还没有准备好,导致@Autowired等注解失效。
初始化和销毁方法
初始化
到目前我们学过三种初始化方法,分别是initMethod
,InitializingBean接口,@PostConstruct三种。我们举例
public class Bean1 implements InitializingBean {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
public void init(){
log.debug("bean的 init方法");
}
@Override
public void afterPropertiesSet() throws Exception {
log.info("InitializingBean 初始化方法");
}
@PostConstruct
public void postConstruct(){
log.debug("postConstruct 初始化方法");
}
}
@SpringBootApplication
public class A07Application {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(A07Application.class, args);
applicationContext.close();
}
@Bean(initMethod = "init")
public Bean1 bean1(){
return new Bean1();
}
}
查看输出日志
2022-05-23 15:00:42.920 DEBUG 18512 --- [ main] com.zhaojun.springsource.a07.Bean1 : postConstruct 初始化方法
2022-05-23 15:00:42.921 INFO 18512 --- [ main] com.zhaojun.springsource.a07.Bean1 : InitializingBean 初始化方法
2022-05-23 15:00:42.921 DEBUG 18512 --- [ main] com.zhaojun.springsource.a07.Bean1 : bean的 init方法
销毁
销毁方法也是三种,destroyMethod
,DisposableBean接口,@PreDestroy
public class Bean1 implements InitializingBean , DisposableBean {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
public void init(){
log.debug("bean的 init方法");
}
@Override
public void afterPropertiesSet() throws Exception {
log.info("InitializingBean 初始化方法");
}
@PostConstruct
public void postConstruct(){
log.debug("postConstruct 初始化方法");
}
@PreDestroy
public void preDestroy(){
log.debug("preDestroy 销毁方法");
}
@Override
public void destroy() throws Exception {
log.debug("destroy 销毁方法");
}
public void destroyMethod() throws Exception {
log.debug("destroyMethod 销毁方法");
}
}
@SpringBootApplication
public class A07Application {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(A07Application.class, args);
applicationContext.close();
}
@Bean(initMethod = "init",destroyMethod = "destroyMethod")
public Bean1 bean1(){
return new Bean1();
}
}
查看日志
2022-05-23 15:09:58.488 DEBUG 6620 --- [ main] com.zhaojun.springsource.a07.Bean1 : preDestroy 销毁方法
2022-05-23 15:09:58.488 DEBUG 6620 --- [ main] com.zhaojun.springsource.a07.Bean1 : destroy 销毁方法
2022-05-23 15:09:58.489 DEBUG 6620 --- [ main] com.zhaojun.springsource.a07.Bean1 : destroyMethod 销毁方法
可以发现,初始化和销毁方法的执行顺序都是,先执行注解的(也就是扩展功能的),然后是接口的,最后是@Bean的。