侧边栏壁纸
  • 累计撰写 106 篇文章
  • 累计创建 3 个标签
  • 累计收到 19 条评论
标签搜索

目 录CONTENT

文章目录

9.Spring底层原理之Aware和InitializingBean接口,后处理器失效

卑微幻想家
2022-05-23 / 0 评论 / 0 点赞 / 149 阅读 / 9,565 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-05-23,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

这一节主要了解Aware接口和InitializingBean接口的作用,常见的Aware接口有:BeanNameAware、BeanFactoryAware、ApplicationContextAware等

Aware接口和InitializingBean的作用

他们的作用如下:

  1. BeanNameAware 注入bean的名字
  2. BeanFactoryAware 注入beanFactory
  3. ApplicationContextAware 注入ApplicationContext
  4. EmbeddedValueResolverAware 解析${}
  5. 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()方法执行了,但是之前的两个方法都没有执行。这是怎么回事呢。我们看看下面的时序图。

image-20220523104758903

正常情况下,是先执行BeanFactory后处理器,然后再进行实例化,但是当配置类包含BeanFactoryPostProcessor时,要创建BeanFactoryPostProcessor必须先实例化,此时的bean后处理器还没有准备好,导致@Autowired等注解失效。

image-20220523104833922

初始化和销毁方法

初始化

到目前我们学过三种初始化方法,分别是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的。

0

评论区