不,你不瞭解Spring實例化bean的時候作了什麼

Spring加載bean的時候構造函數何時調用、@PostConstruct何時調用、實現了BeanPostProcessor接口的bean中的postProcessAfterInitialization和postProcessBeforeInitialization何時調用?你是否清楚呢?若是清楚的話能夠直接忽略該篇文章!!!

最近來了幾個新人,被問了一個和bean生命週期相關的一個知識點,解決新人的問題後本身再寫了一個demo,目的是爲了清晰的描述整個bean的生命週期。git

注意注意,如下demo有五個類,可能會引發部分人不適,建議能夠直接跳到最後看 最終總結,或者本身下載源碼運行下。
demo地址: https://github.com/wiatingpub...

給出一個demo

首先給出一個實現了BeanFactoryPostProcessor的類,目的是爲了比較清晰的看出postProcessBeanFactory接口被調用的時間點。github

/**
 * BeanFactoryPostProcessor是bean工廠的處理器
 */
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    public MyBeanFactoryPostProcessor() {
        super();
        System.out.println("【BeanFactoryPostProcessor】實現類postProcessBeanFactory的構造函數");
    }

    // 容許咱們在工廠裏全部的bean被加載進來後可是還沒初始化前,對全部bean的屬性進行修改也能夠add屬性值,該操做在對應bean的構造函數執行前
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
            throws BeansException {
        System.out
                .println("【BeanFactoryPostProcessor.postProcessBeanFactory】,來自MyBeanFactoryPostProcessor");
        //獲取到Spring中全部的beanName
        String[] beanStr = arg0.getBeanDefinitionNames();
        //循環打印
        for (String beanName : beanStr) {
            System.out.print("bean name:" + beanName + ";");
        }

        System.out.println();
    }
}

這裏給出一個實現了BeanPostProcessor的類,目的是爲了看出postProcessAfterInitialization、postProcessBeforeInitialization調用的時間點。

/**
 * 完成bean實例化、配置以及其餘初始化方法先後要添加一些本身邏輯處理則要實現接口BeanPostProcessor
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    public MyBeanPostProcessor() {
        super();
        System.out.println("【MyBeanPostProcessor】BeanPostProcessor實現類的構造函數");
    }

    // 實例化、依賴注入完畢,在調用顯示的初始化以前完成一些定製的業務
    @Override
    public Object postProcessAfterInitialization(Object arg0, String arg1)
            throws BeansException {

        if (arg0.getClass() == TestBeanA.class || arg0.getClass() == TestBeanB.class) {
            System.out
                    .println("【BeanPostProcessor.postProcessAfterInitialization】來自MyBeanPostProcessor,beanName:" + arg1);
        }
        return arg0;
    }

    // 實例化、依賴注入、初始化後完成一些定製的業務
    @Override
    public Object postProcessBeforeInitialization(Object arg0, String arg1)
            throws BeansException {

        if (arg0.getClass() == TestBeanA.class || arg0.getClass() == TestBeanB.class) {
            System.out
                    .println("【BeanPostProcessor.postProcessBeforeInitialization】來自MyBeanPostProcessor,beanName:" + arg1);
        }
        return arg0;
    }
}

這裏給出繼承了InstantiationAwareBeanPostProcessorAdapter的子類,目的是爲了看出postProcessBeforeInitialization、postProcessAfterInitialization、postProcessPropertyValues被調用的時間點。面試

/**
 * 適配器類,基類是BeanPostProcessor的實現類
 */
@Component
public class MyInstantiationAwareBeanPostProcessor extends
        InstantiationAwareBeanPostProcessorAdapter {

    public MyInstantiationAwareBeanPostProcessor() {
        super();
        System.out
                .println("【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter實現類的構造函數");
    }

    // 接口方法、實例化Bean以前調用
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        if (bean.getClass() == TestBeanA.class || bean.getClass() == TestBeanB.class) {
            System.out
                    .println("【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:" + beanName);

        }
        return bean;
    }

    // 接口方法、實例化Bean以後調用
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        if (bean.getClass() == TestBeanA.class || bean.getClass() == TestBeanB.class) {
            System.out
                    .println("【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:" + beanName);
        }

        return bean;
    }

    // 接口方法、設置某個屬性時調用
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs,
                                                    PropertyDescriptor[] pds, Object bean, String beanName)
            throws BeansException {

        if (bean.getClass() == TestBeanA.class || bean.getClass() == TestBeanB.class) {
            System.out
                    .println("【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:" + beanName);
        }

        return pvs;
    }

這個就牛逼了,直接交給applicationContext.xml注入而且實現了BeanFactoryAware, BeanNameAware,InitializingBean,DisposableBean四個接口類,目的是爲了清晰的看出如下好幾個接口被調用的時間點。spring

public class TestBeanA implements BeanFactoryAware, BeanNameAware,
        InitializingBean, DisposableBean {

    private String name;
    private String address;
    private int phone;

    private BeanFactory beanFactory;
    private String beanName;

    @PostConstruct
    public void init() {
        System.out.println("【TestBeanA.@PostConstruct】");
    }

    public TestBeanA() {
        System.out.println("【TestBeanA.默認構造器】");
    }

    public TestBeanA(String name) {
        System.out.println("【TestBeanA.帶參構造器】");
    }

    public String getName() {
        return name;
    }

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

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getPhone() {
        return phone;
    }

    public void setPhone(int phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "TestBeanA [address=" + address + ", name=" + name + ", phone="
                + phone + "]";
    }

    // 這是BeanFactoryAware接口方法
    @Override
    public void setBeanFactory(BeanFactory arg0) throws BeansException {
        System.out
                .println("【BeanFactoryAware.setBeanFactory】來自TestBeanA");
        this.beanFactory = arg0;
    }

    // 這是BeanNameAware接口方法
    @Override
    public void setBeanName(String arg0) {
        System.out.println("【BeanNameAware.setBeanName】來自TestBeanA");
        this.beanName = arg0;
    }

    // 這是InitializingBean接口方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out
                .println("【InitializingBean.afterPropertiesSet】來自TestBeanA");
    }

    // 這是DiposibleBean接口方法
    @Override
    public void destroy() throws Exception {
        System.out.println("【DiposibleBean.destory】來自TestBeanA");
    }

    // 經過<bean>的init-method屬性指定的初始化方法
    public void myInit() {
        System.out.println("【TestBeanA.myInit】");
    }

    // 經過<bean>的destroy-method屬性指定的初始化方法
    public void myDestory() {
        System.out.println("【TestBeanA.destroy-method】");
    }
}

TestBeanB的做用比較簡單,爲了看出內部數據成員有其餘容器Bean的時候Spring是如何加載bean的。編程

@Component
public class TestBeanB {

    @Autowired
    private TestBeanA testBeanA;

    public TestBeanB() {
        System.out.println("【TestBeanB.默認構造器】");
    }
}

這個是啓動類。緩存

@SpringBootApplication
@ImportResource(locations = {"classpath:applicationContext.xml"})
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

雖然使用的是SpringBoot,這裏還使用xml是爲了看看init-method和destroy-method的調用時間。微信

<?xml version="1.0" encoding="UTF-8"?>
<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 id="testBeanA" class="com.example.demo.bean.TestBeanA" init-method="myInit" destroy-method="myDestory">
        <property name="name" value="關注微信公衆號 飯說編程"/>
    </bean>
</beans>

很長很長的代碼算是都給出來了,接下來看下運行後給出的結果app

【BeanFactoryPostProcessor】實現類postProcessBeanFactory的構造函數
【BeanFactoryPostProcessor.postProcessBeanFactory】,來自MyBeanFactoryPostProcessor
【MyBeanPostProcessor】BeanPostProcessor實現類的構造函數
【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter實現類的構造函數
【TestBeanB.默認構造器】
【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
【TestBeanA.默認構造器】
【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
【BeanNameAware.setBeanName】來自TestBeanA
【BeanFactoryAware.setBeanFactory】來自TestBeanA
【BeanPostProcessor.postProcessBeforeInitialization】來自MyBeanPostProcessor,beanName:testBeanA
【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
【TestBeanA.@PostConstruct】
【InitializingBean.afterPropertiesSet】來自TestBeanA
【TestBeanA.myInit】
【BeanPostProcessor.postProcessAfterInitialization】來自MyBeanPostProcessor,beanName:testBeanA
【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
【BeanPostProcessor.postProcessBeforeInitialization】來自MyBeanPostProcessor,beanName:testBeanB
【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
【BeanPostProcessor.postProcessAfterInitialization】來自MyBeanPostProcessor,beanName:testBeanB
【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
【DiposibleBean.destory】來自TestBeanA
【TestBeanA.destroy-method】

貌似又是一段看完頭暈腦脹的噁心代碼,不過不方不方,直接進入分析階段,跟着分析入手就簡單多了。ide

經過結果分析

首先從函數

【BeanFactoryPostProcessor】實現類postProcessBeanFactory的構造函數
【BeanFactoryPostProcessor.postProcessBeanFactory】,來自MyBeanFactoryPostProcessor
【MyBeanPostProcessor】BeanPostProcessor實現類的構造函數
【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter實現類的構造函數

能夠看出執行順序是:

  • 調用postProcessBeanFactory實現類的構造函數
BeanFactoryPostProcessor是bean工廠的處理器
  • 調用postProcessBeanFactory實現類的postProcessBeanFactory實現函數
postProcessBeanFactory函數容許咱們在工廠裏全部的bean被加載進來後可是還沒初始化前,對全部bean的屬性進行修改也能夠add屬性值
  • 調用BeanPostProcessor實現類的構造函數
完成bean實例化、配置以及其餘初始化方法先後要添加一些本身邏輯處理則要實現接口BeanPostProcessor
  • 調用InstantiationAwareBeanPostProcessorAdapter實現類的構造函數
適配器類,基類是BeanPostProcessor的實現類

再從

【TestBeanB.默認構造器】
【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB

能夠看到,此處spring容器先掃描到了TestBeanB,所以調用順序是

  • TestBeanB的默認構造器【無參構造器】
  • 調用InstantiationAwareBeanPostProcessorAdapter實現類的postProcessPropertyValues接口
postProcessPropertyValues在接口方法、設置某個屬性時調用,經過實驗看到實例化一個Bean的時候也會調用該接口方法

以後實例化TestBeanB的時候發現內部注入了TestBeanA,所以Spring轉而實例化TestBeanA。

接下來看到的是TestBeanA的實例化過程當中調用的順序

【TestBeanA.默認構造器】
【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
【BeanNameAware.setBeanName】來自TestBeanA
【BeanFactoryAware.setBeanFactory】來自TestBeanA
【BeanPostProcessor.postProcessBeforeInitialization】來自MyBeanPostProcessor,beanName:testBeanA
【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
【TestBeanA.@PostConstruct】
【InitializingBean.afterPropertiesSet】來自TestBeanA
【TestBeanA.myInit】
【BeanPostProcessor.postProcessAfterInitialization】來自MyBeanPostProcessor,beanName:testBeanA
【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
  • 調用了TestBeanA的默認構造器
  • 調用InstantiationAwareBeanPostProcessorAdapter實現類的postProcessPropertyValues接口
  • 調用BeanNameAware的setBeanName接口
能夠從源碼看到TestBeanA實現了接口BeanNameAware
  • 調用BeanFactoryAware的setBeanFactory接口
能夠從源碼看到TestBeanA實現了接口BeanFactoryAware
  • 調用BeanPostProcessor的postProcessBeforeInitialization接口
  • 調用InstantiationAwareBeanPostProcessorAdapter的postProcessBeforeInitialization接口
  • 調用TestBeanA中註解了@PostConstruct的函數
  • 調用了InitializingBean的afterPropertiesSet接口
能夠從源碼看到TestBeanA實現了接口InitializingBean
  • 調用了TestBeanA的myInit接口
能夠看到該init-method接口是在applicationContext中init-method配置上的
  • 調用BeanPostProcessor實現類的postProcessAfterInitialization接口
  • 調用InstantiationAwareBeanPostProcessorAdapter子類的postProcessAfterInitialization接口

等TestBeanA實例化結束後,則繼續TestBeanB的實例化路程

【BeanPostProcessor.postProcessBeforeInitialization】來自MyBeanPostProcessor,beanName:testBeanB
【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
【BeanPostProcessor.postProcessAfterInitialization】來自MyBeanPostProcessor,beanName:testBeanB
【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】來自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
  • 調用BeanPostProcessor實現類的postProcessBeforeInitialization接口
  • 調用InstantiationAwareBeanPostProcessorAdapter子類的postProcessBeforeInitialization接口
  • 調用BeanPostProcessor實現類的postProcessAfterInitialization接口
  • 調用InstantiationAwareBeanPostProcessorAdapter子類的postProcessAfterInitialization接口

最後

【DiposibleBean.destory】來自TestBeanA
【TestBeanA.destroy-method】
  • 調用DiposibleBean實現類的destory接口
TestBeanA實現了DiposibleBean接口,實現了destroy接口
  • 調用TestBeanA的myDestory函數
能夠看到該myDestory接口是在applicationContext中destroy-method配置上的。

最終總結

【超重點,面試回答模板,老牛逼了】

  • 若是有bean實現了BeanFactoryPostProcessor接口類,則會實例化該bean,而且調用默認構造器,而後調用postProcessBeanFactory接口
  • 若是有bean實現了BeanPostProcessor接口類,則會先實例化該bean,一樣調用默認構造器
  • 若是有bean繼承了InstantiationAwareBeanPostProcessorAdapter類,則會先實例化該bean,一樣調用默認構造器

以後真正進入一個bean的生命週期過程

  • 先調用bean的默認構造函數
  • 若是有bean繼承了InstantiationAwareBeanPostProcessorAdapter類,此刻會調用postProcessPropertyValues函數
  • 若是這個bean已經實現了BeanNameAware接口,會調用它實現的setBeanName方法,此處傳遞的就是applicationContext.xml配置文件中Bean的id值
  • 若是這個bean已經實現了BeanFactoryAware接口,會調用它實現的setBeanFactory,傳遞的是Spring工廠自身
  • 若是存在其餘bean實現了BeanPostProcessor接口,將會調用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor常常被用做是Bean內容的更改,而且因爲這個是在Bean初始化結束時調用那個的方法,也能夠被應用於內存或緩存技術;
  • 若是存在其餘bean繼承了InstantiationAwareBeanPostProcessorAdapter類,則會調用postProcessBeforeInitialization接口
  • 若是這個bean中有函數加了@PostConstruct註解,則該函數會在此刻被調用
  • 若是這個bean實現了InitializingBean接口重寫了afterPropertiesSet方法,該方法會在此刻被調用
  • 若是這個bean在Spring配置文件中配置了init-method屬性,則會自動調用其配置的初始化方法。
  • 若是存在其餘bean實現了BeanPostProcessor接口,將會調用postProcessAfterInitialization(Object obj, String s)方法
  • 若是存在其餘bean繼承了InstantiationAwareBeanPostProcessorAdapter類,則會調用postProcessAfterInitialization接口
走到這一步之後就能夠應用這個Bean了,而這個Bean是一個Singleton的,雖然在Spring配置文件中也能夠配置非Singleton,這裏不作贅述。

走入銷燬階段

  • 當bean再也不須要時,會通過清理階段,若是這個bean實現了DisposableBean接口,會調用其實現的destroy()方法;
  • 若是這個bean的applicationContext.xml配置中配置了destroy-method屬性,會自動調用其配置的銷燬方法。

Java源碼分析、go語言應用、微服務,更多幹貨歡迎關注公衆號:
公衆號.jpg

相關文章
相關標籤/搜索