Spring中Bean的生命週期

Spring生態目前發展很快,Spring、Spring Boot、Spring Cloud、Spring Data等等愈來愈豐富,而且迭代也很快。
最近在找工做,面試過程當中常常有問到Spring的基礎知識,其中一個知識點就是Spring中Bean的生命週期。java

若是沒有準備,忽然問這道題有點答不上來。大概想的話就是先執行構造函數,執行一些接口方法(好比ContextAware、afterPropertiesSet),
而後執行@PostConstruct標記的方法,最後執行destroy方法(若是有的話)。面試

日常工做中:
@PostConstruct有用到過,在類構造完成後用來執行一些自定義的初始化邏輯;
afterPropertiesSet記得在Spring提供的類裏常常有看到;
ApplicationContextAware接口有在工具類用到,經過定義一個static變量和方法來獲Spring的Context。spring

找到一張圖:
app

寫個Bean類來測試一下:ide

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次。post

嘗試把版本下降點,改成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還有待研究,暫時沒有找到這個問題的緣由.this

加深一下印象,基礎知識確實應常常溫習、總結。加油!

相關文章
相關標籤/搜索