如何理解 SpringBoot 的生命周期

生命周期,就是从诞生到死亡的一个过程。Spring 中 bean 也是如此。在 Spring 中的 ConfigurableApplicationContext 的 refresh 开始直到一个 bean 可以被正常使用,中间经历了一系列初始化操作;而在其 close 后又经历了一系列销毁操作,这被称之为 Spring 中 bean 的生命周期。

周期

Spring 中的 bean 经历了以下阶段:

如何理解 SpringBoot 的生命周期_第1张图片

其中红色的框不属于 Spring 来管理了。

实例化

实例化就是 Spring 通过反射来调用构造方法来实例化一个对象。

初始化

Spring 的初始化有两种方式,一种是实现 InitializingBean 接口,另一种是在一个方法上面加上 @PostConstruct 注解表示这是一个初始化方法。

销毁

Spring 的销毁对象的方式也有两种,一种是实现 DisposableBean,另一种是在一个方法上加 @PreDestroy 注解;和 初始化 的两种方式相对应。

顺序

具体顺序是如何,我们用一段代码就可以看到。

// NormalEntity.java 这是一个将往 Spring 中注入的类
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class NormalEntity implements InitializingBean, DisposableBean {

    public NormalEntity() {
        System.out.println("NormalEntity constructor...");
    }

    @PostConstruct
    public void init() {
        System.out.println("NormalEntity PostConstruct");
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("NormalEntity preDestroy");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("NormalEntity afterPropertiesSet");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("NormalEntity destroy");
    }
}

// MainConfig.java
import org.springframework.context.annotation.Bean;

public class MainConfig {

    @Bean
    public NormalEntity normalEntity() {
        return new NormalEntity();
    }
}
// MainTest.java 这里是启动类
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        NormalEntity bean = applicationContext.getBean(NormalEntity.class);
        System.out.println(bean);
        // 这里使用的是 AnnotationConfigApplicationContext,需要手动调用 close
        // 如果是 SpringBoot 项目,会自动注册 shutdown hook,里面调用了 close 方法
        applicationContext.close();
    }
}

会看到控制台打印出了结果,也展示了调用顺序:

NormalEntity constructor...
NormalEntity PostConstruct
NormalEntity afterPropertiesSet
NormalEntity preDestroy
NormalEntity destroy

代码的调用

在构造方法下一个断点,就可以根据调用栈知道调用路径了。

下面简要说明几处。

AbstractApplicationContext#finishBeanFactoryInitialization(ConfigurableListableBeanFactory)

实例化所有剩下的非懒加载的单例bean
AbstractApplicationContext#refresh 方法的倒数第二步调用了此方法来实例化容器中所有的非懒加载的bean(懒加载的肯定是用到的时候再实例化),这里就最终可以到AbstractBeanFactory#doGetBean(String, Class, Object[], boolean)里面的getSingleton(String, ObjectFactory),那最终其实就是调用参数ObjectFactory提供的createBean(String, RootBeanDefinition, Object[])方法。

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean(String, RootBeanDefinition, Object[])

  1. 调用createBeanInstance(String, RootBeanDefinition, Object[])方法来使用构造方法实例化对象;
  2. 在下面的applyMergedBeanDefinitionPostProcessors(RootBeanDefinition, Class, String)中使用BeanPostProcessor调用有注解的初始化方法;
  3. initializeBean(String, Object, RootBeanDefinition)方法中调用了实现了InitializingBean接口的afterPropertiesSet方法

经历以上三步骤,bean的初始化完成。

同时如果想要知道Spring的bean在销毁时做了什么,可以在另外两个销毁方法下断点,就可以知道了。

你可能感兴趣的:(SpringBoot,spring,boot,java,后端,spring)