Spring中Bean的生命周期

Spring生态目前发展很快,Spring、Spring Boot、Spring Cloud、Spring Data等等越来越丰富,并且迭代也很快。
最近在找工作,面试过程中经常有问到Spring的基础知识,其中一个知识点就是Spring中Bean的生命周期。

如果没有准备,突然问这道题有点答不上来。大概想的话就是先执行构造函数,执行一些接口方法(比如ContextAware、afterPropertiesSet),
然后执行@PostConstruct标记的方法,最后执行destroy方法(如果有的话)。

平常工作中:
@PostConstruct有用到过,在类构造完成后用来执行一些自定义的初始化逻辑;
afterPropertiesSet记得在Spring提供的类里经常有看到;
ApplicationContextAware接口有在工具类用到,通过定义一个static变量和方法来获Spring的Context。

找到一张图:

写个Bean类来测试一下:

package com.cdfive.learning.spring;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;

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

/**
 * Test for Spring Bean lifecycle
 *
 * @author cdfive
 * @date 2019-04-09
 */
@Component
public class BeanLifecycle implements BeanNameAware, BeanFactoryAware, ApplicationContextAware
        , BeanPostProcessor, InitializingBean, DisposableBean {

    private static int STEP = 0;

    private String name;

    private Integer age;

    public static void main(String[] args) {
        // Close the log
        LoggerContext loggerContext= (LoggerContext) LoggerFactory.getILoggerFactory();
        ch.qos.logback.classic.Logger logger=loggerContext.getLogger("root");
        logger.setLevel(Level.OFF);

        // Create a Spring ApplicationContext and start
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext("com.cdfive.learning.spring");
        ctx.start();

        // Close the ApplicationContext
        ctx.close();
    }

    public BeanLifecycle() {
        print("constructor");
    }

    @PostConstruct
    public void postConstruct() {
        print("@PostConstruct");
    }

    @PreDestroy
    public void preDestroy() {
        print("@PreDestroy");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        print("BeanFactoryAware=>setBeanFactory");
    }

    @Override
    public void setBeanName(String s) {
        print("BeanNameAware=>setBeanName");
    }

    @Override
    public void destroy() throws Exception {
        print("DisposableBean=>destroy");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        print("InitializingBean=>afterPropertiesSet");
    }

    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        print("BeanPostProcessor=>postProcessBeforeInitialization");
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        print("BeanPostProcessor=>postProcessAfterInitialization");
        return null;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        print("ApplicationContextAware=>setApplicationContext");
    }

    private static void print(String s) {
        System.out.println((++STEP) + "." + s);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

SpringBoot 2.0.5.RELEASE(即Spring 5.0.9.RELEASE)输出如下:

1.constructor
2.BeanNameAware=>setBeanName
3.BeanFactoryAware=>setBeanFactory
4.ApplicationContextAware=>setApplicationContext
5.@PostConstruct
6.InitializingBean=>afterPropertiesSet
7.BeanPostProcessor=>postProcessBeforeInitialization
8.BeanPostProcessor=>postProcessAfterInitialization
9.BeanPostProcessor=>postProcessBeforeInitialization
10.BeanPostProcessor=>postProcessAfterInitialization
11.@PreDestroy
12.DisposableBean=>destroy

可以看到,基本跟那张图一致。

不过有一点很奇怪的是BeanPostProcessor的postProcessBeforeInitialization、postProcessAfterInitialization执行了2次。

尝试把版本降低点,改为1.5.10.RELEASE(即Spring 4.3.14.RELEASE)输出如下:

1.constructor
2.BeanNameAware=>setBeanName
3.BeanFactoryAware=>setBeanFactory
4.ApplicationContextAware=>setApplicationContext
5.@PostConstruct
6.InitializingBean=>afterPropertiesSet
7.BeanPostProcessor=>postProcessBeforeInitialization
8.BeanPostProcessor=>postProcessBeforeInitialization
9.@PreDestroy
10.DisposableBean=>destroy

其中BeanPostProcessor的postProcessBeforeInitialization执行了2次,postProcessAfterInitialization没有执行。
关于BeanPostProcessor还有待研究,暂时没有找到这个问题的原因.

加深一下印象,基础知识确实应经常温习、总结。加油!

原文地址:https://www.cnblogs.com/cdfive2018/p/10684164.html