Spring Bean 的生命周期是怎样的?

 作者简介:大家好,我是码炫码哥,前中兴通讯、美团架构师,现任某互联网公司CTO,兼职码炫课堂主讲源码系列专题


代表作:《jdk源码&多线程&高并发》,《深入tomcat源码解析》,《深入netty源码解析》,《深入dubbo源码解析》,《深入springboot源码解析》,《深入spring源码解析》,《深入redis源码解析》等


联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬。码炫课堂的个人空间-码炫码哥个人主页-面试,源码等

“请你描述下 Spring Bean 的生命周期?”,这是 Spring 中一个很常见的面试题。Spring Bean 从出生到销毁的全过程就是它的整个生命周期,它一共会经历以下四个阶段:

  • 实例化 Instantiation
  • 属性赋值 Populate
  • 初始化 Initialization
  • 销毁 Destruction

如下:

四个阶段共分为 10 个小步骤:

  1. 实例化:第 1 步,实例化一个 Bean 对象。
  2. 属性赋值:第2 步,为该 Bean 对象设置属性并注入依赖。
  3. 初始化:这步骤要处理的事情比较多:
    1. 检查 Aware 的相关接口并设置相关依赖:当一个Bean实现了Aware 的相关接口,Spring容器会在初始化过程中自动调用相应的方法,为Bean注入特定的对象或信息。这些接口允许Bean获取到Spring容器的一些内部工作情况,比如环境配置、文件资源、应用上下文等。
    2. BeanPostProcessor 前后置处理
      • 在Bean的自定义初始化方法执行之前,Spring容器会调用BeanPostProcessorspostProcessBeforeInitialization() 方法,它允许在Bean初始化前进行一些自定义的操作。
      • 在Bean的自定义初始化方法执行之后,Spring容器会调用BeanPostProcessorspostProcessAfterInitialization(),它允许在Bean初始化后进行一些自定义的操作。
    3. 步骤 5、6 是真正的初始化操作,它主要分为三个部分:
      • 如果在XML配置中使用了init-method属性,Spring会调用指定的方法作为Bean的初始化方法。
      • 如果使用了@PostConstruct注解,Spring会在依赖注入完成后调用被该注解标记的方法。
      • 如果Bean实现了InitializingBean接口,那么Spring将会在设置所有属性后调用afterPropertiesSet()
  • 销毁:步骤 8 其实算不上真正的销毁操作,它这是在使用前注册了销毁的相关调用接口,为后面的第 9、10 步真正销毁 Bean 是在执行相应的方法。

我们再结合源码看下,AbstractAutowireCapableBeanFactory#doCreateBean()

  protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {

    //阶段一:实例化 Bean
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
      instanceWrapper = createBeanInstance(beanName, mbd, args);
    }

    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
      // 阶段二:属性赋值
      populateBean(beanName, mbd, instanceWrapper);
      
      // 阶段三:初始化
      exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
     //...
    }

    // 销毁-注册回调接口
    try {
      registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
      throw new BeanCreationException(
          mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }

    return exposedObject;
  }

其中初始化阶段又稍微复杂点,我们进入 initializeBean() 看下:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    // 3. 检查 Aware 相关接口并设置相关依赖
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        invokeAwareMethods(beanName, bean);
    }

    // 4. BeanPostProcessor 前置处理
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    // 5. 若实现 InitializingBean 接口,调用 afterPropertiesSet() 方法
    // 6. 若配置自定义的 init-method方法,则执行
    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
    }
    // 7. BeanPostProceesor 后置处理
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

阶段四:销毁,源码如下:

// DisposableBeanAdapter.java
public void destroy() {
    // 9. 若实现 DisposableBean 接口,则执行 destory()方法
    if (this.invokeDisposableBean) {
        try {
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                    ((DisposableBean) this.bean).destroy();
                    return null;
                }, this.acc);
            }
            else {
                ((DisposableBean) this.bean).destroy();
            }
        }
    }
    
  // 10. 若配置自定义的 detory-method 方法,则执行
    if (this.destroyMethod != null) {
        invokeCustomDestroyMethod(this.destroyMethod);
    }
    else if (this.destroyMethodName != null) {
        Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
        if (methodToInvoke != null) {
            invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
        }
    }
}

下面我们来看一个例子,用这个例子来演示一个 Bean 的一生。

  • 新建一个 Bean
public class SkSpringBeanLifeCycle implements InitializingBean, BeanFactoryAware, BeanNameAware, DisposableBean {
    private String name;

    private String website;

    public SkSpringBeanLifeCycle(){
        System.out.println("调用构造函数,实例化...");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("设置属性;name = " +name);
        this.name = name;
    }

    public String getWebsite() {
        return website;
    }

    public void display(){
        System.out.println("调用方法.....");
    }

    public void setWebsite(String website) {
        System.out.println("设置属性;website = " + website);
        this.website = website;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("BeanFactoryAware 被调用...");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("BeanNameAware 被调用...");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean destroy 被调用...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean afterPropertiesSet 被调动...");
    }

    public void initMethod(){
        System.out.println("init-method 被调用...");
    }

    public void destroyMethod(){
        System.out.println("destroy-method 被调用...");
    }
}

该 Bean 有两个属性:name 和 website。且实现了接口InitializingBeanBeanFactoryAwareBeanNameAwareDisposableBean,其中 InitializingBean 是初始化化接口,BeanFactoryAwareBeanNameAware 是两个 Aware 类接口,DisposableBean 是销毁时的接口。

  • 再定义一个 Bean 实现 BeanPostProcessor 接口,进行 Bean 初始化阶段的前后置处理:
public class SkSpringBeanLifeCycleProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor postProcessBeforeInitialization 被调用...");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor postProcessAfterInitialization 被调用...");
        return bean;
    }
}
  • 为了更容易地测试,我们使用 XML 配置文件:
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="skSpringBeanLifeCycleProcessor" class="com.skjava.admin.dto.SkSpringBeanLifeCycleProcessor"/>

    <bean name="skSpringBeanLifeCycle" class="com.skjava.admin.dto.SkSpringBeanLifeCycle"
          init-method="initMethod" destroy-method="destroyMethod">
        <property name="name" value= "死磕 Java"/>
        <property name="website" value="https://skjava.com" />
    </bean>

</beans>
  • 测试类:
public class SkSpringBeanLifeCycleTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        SkSpringBeanLifeCycle beanLifeCycle = (SkSpringBeanLifeCycle) context.getBean("skSpringBeanLifeCycle");
        System.out.println("Bean 初始化完成,调用其方法...");
        beanLifeCycle.display();
        System.out.println("方法调用完成,容器开始关闭....");
        ((ClassPathXmlApplicationContext) context).destroy();
    }
}
  • 执行结果:
调用构造函数,实例化...

设置属性;name = 死磕 Java
设置属性;website = https://skjava.com

BeanNameAware 被调用...
BeanFactoryAware 被调用...

BeanPostProcessor postProcessBeforeInitialization 被调用...

InitializingBean afterPropertiesSet 被调动...

init-method 被调用...

BeanPostProcessor postProcessAfterInitialization 被调用...

Bean 初始化完成,调用其方法...
调用方法.....
方法调用完成,容器开始关闭....

DisposableBean destroy 被调用...

destroy-method 被调用...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值