bean在Spring容器中的生命周期详解-the lifecycle of a bean in a Spring container(为什么实现了BeanPostProcessor没回调)

前言

Spring容器帮我们维护Bean的生命周期,通过DI维护对象之间的关联,实现组件之间的松耦合。程序与框架之间的“协议”,是我们可以充分利用框架提供的功能,实现场景化需求的关键结合点。
对于Bean的创建,我们需要理解的是,一个bean在spring容器中的生命周期,Spring在bean生命周期提供给我们什么样的接口,或者说不同回调时机可供我们使用。

bean的XML定义:

<bean id="bean1" class="com.test.bean.Bean1" init-method="appInit" destroy-method="appDestroy"></bean>

Bean1.java

public class Bean1 implements BeanNameAware, BeanFactoryAware,ApplicationContextAware,BeanPostProcessor, InitializingBean, DisposableBean {

    public void appInit() {
        System.out.println("Bean1: appInit()");
    }

    public void announce() {
        System.out.println("in executing bean1 method");
    }

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean1: postProcessBeforeInitialization(): " + beanName);
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean1: postProcessAfterInitialization(): " + beanName);
        return bean;
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("Bean1: afterPropertiesSet()");
    }

    public void destroy() throws Exception {
        System.out.println("Bean1: destroy()");
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("Bean1: setBeanFactory(): " + beanFactory.toString());
    }

    public void setBeanName(String s) {
        System.out.println("Bean1: setBeanName(): " + s);
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("Bean1: setApplicationContext(): " + applicationContext.toString());
    }

    public void appDestroy() {
        System.out.println("Bean1: appDestroy()");
    }
}

创建Spring ApplicationContext

public class TestEntry {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean-conf.xml");

        Bean1 bean1 = context.getBean(Bean1.class);
        bean1.announce();

        context.close();
    }
}

输出如下:
在这里插入图片描述
根据《Spring In Action,4th》中,我们归纳bean的生命周期为以下:

  1. Spring instantiates the bean.
    Spring实例化 bean对象;
  2. Spring injects values and bean references into the bean’s properties
    Spring处理相关值的注入,以及引用成员的注入;
  3. If the bean implements BeanNameAware, Spring passes the bean’s ID to the set-
    BeanName() method
    如果bean实现了BeanNameAware接口,则调用 setBeanName 方法;
  4. If the bean implements BeanFactoryAware, Spring calls the setBeanFactory()
    method, passing in the bean factory itself
    如果bean实现了BeanFactoryAware接口,则调用setBeanFactory 方法;
  5. If the bean implements ApplicationContextAware, Spring calls the set-
    ApplicationContext() method, passing in a reference to the enclosing appli-
    cation context
    如果bean实现了 ApplicationContextAware 接口,则调用setApplicationContext
    方法;
  6. If the bean implements the BeanPostProcessor interface, Spring calls its post-
    ProcessBeforeInitialization() method.
    如果bean实现了BeanPostProcessor接口,则调用 postProcessBeforeInitialization
  7. If the bean implements the InitializingBean interface, Spring calls its after-
    PropertiesSet() method
    如果bean实现了InitializingBean接口,则调用 afterPropertiesSet 方法
  8. if the bean was declared with an init-method, then the specified initialization method is called
    如果bean定义了init-method,则调用bean的初始化方法(这里为appInit)
  9. If the bean implements BeanPostProcessor, Spring calls its postProcess-
    AfterInitialization() method
    如果bean实现了BeanPostProcessor接口,则调用postProcessAfterInitialization方法
  10. At this point, the bean is ready to be used by the application and remains in the application context until the application context is destroyed
    至此,bean已经可以在程序中使用,直到应用上下文关闭
  11. If the bean implements the DisposableBean interface, Spring calls its destroy() method
    如果实现了 DisposableBean接口,则调用 destroy方法
  12. if the bean was declared with a destroy-method, the specified method is called
    如果声明了destroy-method,则调用该方法(这里为appDestroy)

总结一下,
第一类,是框架通知程序的一些接口,即***Aware接口的;
第二类,Spring初始化bean的不同时机阶段

有个地方好像不对?!

我们的示例代码里,bean实现了BeanPostProcessor接口,但是并没有出现 6 和 9的相关调用日志。按照《Spring In Action》的相关描述,
在这里插入图片描述
按照字面意思理解,如果一个bean实现了BeanPostProcessor接口,Spring回调用相关的方法的。。但是。。。哪里出了问题?

让我们再添加一个bean

public class Bean3 implements
        BeanPostProcessor, InitializingBean, DisposableBean {

    public void init() {
        System.out.println("Bean3: init method");
    }

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean3: postProcessBeforeInitialization: " + beanName);
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean3: postProcessAfterInitialization: " + beanName);
        return bean;
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("Bean3: afterPropertiesSet: ");
    }

    public void destroy() throws Exception {
        System.out.println("Bean3: destroy: ");
    }
}

声明一下:

<bean class="com.test.bean.Bean3" init-method="init"></bean>

来看运行情况:
在这里插入图片描述
bean1先创建,bean3接着创建,还是没有出现期望的 BeanPostProcessor 两个回调。

What the FXCK happened?

以上创建的两个bean,都是实现了 BeanPostProcessor 接口的,我们再加一个未实现BeanPostProcessor接口的bean看看。。

public class Bean2 implements InitializingBean, DisposableBean {
    public void init() {
        System.out.println("Bean2: init method");
    }

    public void destroy() throws Exception {
        System.out.println("Bean2:destroy");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("Bean2:afterPropertiesSet");
    }
}

声明一下,

<bean class="com.test.bean.Bean2" init-method="init"></bean>

看下运行日志,注意红框的部分!
在这里插入图片描述

实现了BeanPostProcessor接口的bean1和bean3,看到了我们期望中的回调日志!!
同时注意一下,回调时传入的Bean是谁,是Bean2!!!

总结:这是怎么回事?

首先,从实例运行情况看:
1. 如果所有的bean都实现了 BeanPostProcessor 接口,没有回调;
2. 如果还有其他的bean,比如实例中的bean2,其未实现 BeanPostProcessor 接口,那么Spring会回调所有实现了 BeanPostProcessor 接口的bean的相应方法,而且,传入的bean参数就是bean2;

从结果来看,画个简图总结下,

在这里插入图片描述
Bean1和Bean3实现了BeanPostProcessor接口,Bean2未实现该接口,Bean2在创建过程中,Spring回调了所有实现了 BeanPostProcessor 接口的Bean的方法,传入Bean2!!!

所以,BeanPostProcessor接口机制的使用场景:
如果一个Bean的创建(Bean2),想要通知到与其相关的其他Bean(如Bean1和Bean3),也就是让想知道这个事的Bean知道,那么就让这些Bean(Bean1和Bean3)注册BeanPostProcessor,也就是实现 BeanPostProcessor接口。这样,Bean2创建的时候,想知道的人都会收到来自Spring管家的回调通知啦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值