Spring Bean生命周期和重要接口之概述


1 Bean生命周期

1.1 概述

Spring Bean的生命周期對Spring框架原理理解的重要性,所以接下來我們就來分析一下Bean生命周期的整體流程。首先Bean就是一些Java對象,只不過這些Bean不是我們主動new出來的,而是交個Spring IOC容器創建並管理的,因此Bean的生命周期受Spring IOC容器控制,Bean生命周期大致分為以下幾個階段:
圖片

  • Bean的實例化(Instantiation):Spring框架會取出BeanDefinition的信息進行判斷當前Bean的范圍是否是singleton的,是否不是延遲加載的,是否不是FactoryBean等,最終將一個普通的singleton的Bean通過反射進行實例化
    點擊了解 Spring Bean生命周期之(1)BeanDefinition
    點擊了解 Spring Bean生命周期之(2)實例化( Instantiation)
  • Bean的屬性賦值(Populate):Bean實例化之后還僅僅是個"半成品",還需要對Bean實例的屬性進行填充,Bean的屬性賦值就是指 Spring 容器根據BeanDefinition中屬性配置的屬性值注入到 Bean 對象中的過程。
    點擊了解 Spring Bean生命周期之(3)populateBean 屬性填充階段
  • Bean的初始化(Initialization):對Bean實例的屬性進行填充完之后還需要執行一些Aware接口方法、執行BeanPostProcessor方法、執行InitializingBean接口的初始化方法、執行自定義初始化init方法等。該階段是Spring最具技術含量和復雜度的階段,並且Spring高頻面試題Bean的循環引用問題也是在這個階段體現的;
  • Bean的使用階段:經過初始化階段,Bean就成為了一個完整的Spring Bean,被存儲到單例池singletonObjects中去了,即完成了Spring Bean的整個生命周期,接下來Bean就可以被隨心所欲地使用了。
  • Bean的銷毀(Destruction):Bean 的銷毀是指 Spring 容器在關閉時,執行一些清理操作的過程。在 Spring 容器中, Bean 的銷毀方式有兩種:銷毀方法destroy-methodDisposableBean 接口。

1.2 Bean實例化階段

我們在springBeanFactory工廠列舉了很多接口,代表着bean的生命周期,我們主要記住的是圈紅線圈出來的接口, 再結合spring的源碼來看這些接口主要是在哪里調用的
在這里插入圖片描述

AbstractAutowireCapableBeanFactory類的doCreateBean方法是創建bean的開始,我們可以看到首先需要實例化這個bean,也就是在堆中開辟一塊內存空間給這個對象,createBeanInstance方法里面邏輯大概就是采用反射生成實例對象,進行到這里表示對象還並未進行屬性的填充,也就是@Autowired注解的屬性還未得到注入

1.2.1 兩個階段

Spring將管理的一個個的依賴對象稱之為Bean,這從xml配置文件中也可以看出。
Spring IOC容器就好像一個生產產品的流水線上的機器,Spring創建出來的Bean就好像是流水線的終點生產出來的一個個精美絕倫的產品。既然是機器,總要先啟動,Spring也不例外。因此Bean的一生從總體上來說可以分為兩個階段:

  • 容器啟動階段
  • Bean實例化階段

容器的啟動階段做了很多的預熱工作,為后面Bean的實例化做好了充分的准備,我們首先看一下容器的啟動階段都做了哪些預熱工作。

1.2.2 容器啟動階段

1.2.2.1 配置元信息

我們說Spring IOC容器將對象實例的創建與對象實例的使用分離,我們的業務中需要依賴哪個對象不再依靠我們自己手動創建,只要向Spring要,Spring就會以注入的方式交給我們需要的依賴對象。

既然我們將對象創建的任務交給了Spring,那么Spring就需要知道創建一個對象所需要的一些必要的信息。而這些必要的信息可以是Spring過去支持最完善的xml配置文件,或者是其他形式的例如properties的磁盤文件,也可以是現在主流的注解,甚至是直接的代碼硬編碼。總之,這些創建對象所需要的必要信息稱為配置元信息。

<bean id="role" class="com.wbg.springxmlbean.entity.Role">
    <!-- property元素是定義類的屬性,name屬性定義的是屬性名稱 value是值
    相當於:
    Role role=new Role();
    role.setId(1);
    role.setRoleName("高級工程師");
    role.setNote("重要人員");-->
    <property name="id" value="1"/>
    <property name="roleName" value="高級工程師"/>
    <property name="note" value="重要人員"/>
</bean>

1.2.2.2 BeanDefination

我們大家都知道,在Java世界中,萬物皆對象,散落於程序代碼各處的注解以及保存在磁盤上的xml或者其他文件等等配置元信息,在內存中總要以一種對象的形式表示,就好比我們活生生的人對應到Java世界中就是一個Person類。
Spring選擇在內存中表示這些配置元信息的方式就是BeanDefination,這里我們只是需要知道配置元信息被加載到內存之后是以BeanDefination的形存在的

1.2.2.3 BeanDefinationReader

大家肯定很好奇,我們是看得懂Springxml配置文件中一個個的Bean定義,但是Spring是如何看懂這些配置元信息的呢?這個就要靠我們的BeanDefinationReader了。

不同的BeanDefinationReader就像葫蘆兄弟一樣,各自擁有各自的本領。如果我們要讀取xml配置元信息,那么可以使用XmlBeanDefinationReader。如果我們要讀取properties配置文件,那么可以使用PropertiesBeanDefinitionReader加載。而如果我們要讀取注解配置元信息,那么可以使用 AnnotatedBeanDefinitionReader加載。我們也可以很方便的自定義BeanDefinationReader來自己控制配置元信息的加載。假如我們的配置元信息現有的不能滿足,那么我們可以自定義From BeanDefinationReader

總的來說,BeanDefinationReader的作用就是加載配置元信息,並將其轉化為內存形式的BeanDefination,存在某一個地方

1.2.2.4 BeanDefinationRegistry

執行到這里,總算不遺余力的將存在於各處的配置元信息加載到內存,並轉化為BeanDefination的形式,這樣我們需要創建某一個對象實例的時候,找到相應的BeanDefination然后創建對象即可。那么我們需要某一個對象的時候,去哪里找到對應的BeanDefination呢?

這種通過Bean定義的id找到對象的BeanDefination的對應關系或者說映射關系又是如何保存的呢?這就引出了BeanDefinationRegistry了。
Spring通過BeanDefinationReader將配置元信息加載到內存生成相應的BeanDefination之后,就將其注冊到BeanDefinationRegistry中,BeanDefinationRegistry就是一個存放BeanDefination的大籃子,它也是一種鍵值對的形式,通過特定的Bean定義的id,映射到相應的BeanDefination

1.2.2.5 BeanFactoryPostProcessor

BeanFactoryPostProcessor是容器啟動階段Spring提供的一個擴展點,主要負責對注冊到BeanDefinationRegistry中的一個個的BeanDefination進行一定程度上的修改與替換。

例如我們的配置元信息中有些可能會修改的配置信息散落到各處,不夠靈活,修改相應配置的時候比較麻煩,這時我們可以使用占位符的方式來配置。例如配置Jdbc的DataSource連接的時候可以這樣配置:

<bean id="dataSource"  
    class="org.apache.commons.dbcp.BasicDataSource"  
    destroy-method="close">  
    <property name="maxIdle" value="${jdbc.maxIdle}"></property>  
    <property name="maxActive" value="${jdbc.maxActive}"></property>  
    <property name="maxWait" value="${jdbc.maxWait}"></property>  
    <property name="minIdle" value="${jdbc.minIdle}"></property>  
  
    <property name="driverClassName"  
        value="${jdbc.driverClassName}">  
    </property>  
    <property name="url" value="${jdbc.url}"></property>  
  
    <property name="username" value="${jdbc.username}"></property>  
    <property name="password" value="${jdbc.password}"></property>  
</bean> 

BeanFactoryPostProcessor就會對注冊到BeanDefinationRegistry中的BeanDefination做最后的修改,替換$占位符為配置文件中的真實的數據。

至此,整個容器啟動階段就算完成了,容器的啟動階段的最終產物就是注冊到BeanDefinationRegistry中的一個個BeanDefination了,這就是Spring為Bean實例化所做的預熱的工作。讓我們再通過一張圖的形式回顧一下容器啟動階段都是搞了什么事吧。

1.2.3 BeanDefination總結圖示

在這里插入圖片描述

1.2.4 Bean實例化階段

需要指出,容器啟動階段與Bean實例化階段存在多少時間差,如果我們選擇懶加載的方式,那么直到我們伸手向Spring要依賴對象實例之前,其都是以BeanDefinationRegistry中的一個個的BeanDefination的形式存在,也就是Spring只有在我們需要依賴對象的時候才開啟相應對象的實例化階段。

而如果我們不是選擇懶加載的方式,容器啟動階段完成之后,將立即啟動Bean實例化階段,通過隱式的調用所有依賴對象的getBean方法來實例化所有配置的Bean並保存起來。

1.2.4.1 對象創建策略

對象的創建采用了策略模式,借助我們前面BeanDefinationRegistry中的BeanDefination,我們可以使用反射的方式創建對象,也可以使用CGlib字節碼生成創建對象。
同時我們可以靈活的配置來告訴Spring采用什么樣的策略創建指定的依賴對象。Spring中Bean的創建是策略設計模式的經典應用。這個時候,內存中應該已經有一個我們想要的具體的依賴對象的實例了,但是故事的發展還沒有我們想象中的那么簡單。

1.2.4.2 BeanWrapper——對象的外衣

Spring中的Bean並不是以一個個的本來模樣存在的,由於Spring IOC容器中要管理多種類型的對象,因此為了統一對不同類型對象的訪問,Spring給所有創建的Bean實例穿上了一層外套,這個外套就是BeanWrapper

BeanWrapper實際上是對反射相關API的簡單封裝,使得上層使用反射完成相關的業務邏輯大大的簡化,我們要獲取某個對象的屬性,調用某個對象的方法,現在不需要在寫繁雜的反射API了以及處理一堆麻煩的異常,直接通過BeanWrapper就可以完成相關操作

1.3 Bean屬性填充

上一步包裹在BeanWrapper中的對象還是一個少不經事的孩子,需要為其設置屬性以及依賴對象

  • 基本類型屬性 : 如果配置元信息中有配置,那么將直接使用配置元信息中的設置值賦值即可,即使基本類型的屬性沒有設置值,那么得益於JVM對象實例化過程,屬性依然可以被賦予默認的初始化零值。
  • 引用類型屬性 : Spring會將所有已經創建好的對象放入一個Map結構中,此時Spring會檢查所依賴的對象是否已經被納入容器的管理范圍之內,也就是Map中是否已經有對應對象的實例了。如果有,那么直接注入,如果沒有,那么Spring會暫時放下該對象的實例化過程,轉而先去實例化依賴對象,再回過頭來完成該對象的實例化過程
    在這里插入圖片描述

我們可以看到第二步就是填充bean的成員屬性,populateBean方法里面的邏輯大致就是對使用到了注入屬性的注解就會進行注入,如果在注入的過程發現注入的對象還沒生成,則會跑去生產要注入的對象,第三步就是調用initializeBean方法初始化bean,也就是調用我們上述所提到的接口

1.4 Bean初始化階段

Bean初始化階段中重要接口
在這里插入圖片描述

在這里插入圖片描述

可以看到initializeBean方法中,首先調用的是使用的Aware接口的方法,我們具體看一下invokeAwareMethods方法中會調用Aware接口的那些方法

1.4.1 Aware相關接口

在這里插入圖片描述

我們可以知道如果我們實現了BeanNameAwareBeanClassLoaderAwareBeanFactoryAware三個Aware接口的話,會依次調用setBeanName(), setBeanClassLoader(), setBeanFactory()方法,再看applyBeanPostProcessorsBeforeInitialization源碼

1.4.2 BeanPostProcessors相關接口

在這里插入圖片描述

發現會如果有類實現了BeanPostProcessor接口,就會執行postProcessBeforeInitialization方法,這里需要注意的是:如果多個類實現BeanPostProcessor接口,那么多個實現類都會執行postProcessBeforeInitialization方法,可以看到是for循環依次執行的,還有一個注意的點就是如果加載A類到spring容器中,A類也重寫了BeanPostProcessor接口的postProcessBeforeInitialization方法,這時要注意A類的postProcessBeforeInitialization方法並不會得到執行,因為A類還未加載完成,還未完全放到springsingletonObjects一級緩存中。

再看一個注意的點

在這里插入圖片描述

圖片

可以看到ApplicationContextAwareProcessor也實現了BeanPostProcessor接口,重寫了postProcessBeforeInitialization方法,方法里面並調用了invokeAwareInterfaces方法,而invokeAwareInterfaces方法也寫着如果實現了眾多的Aware接口,則會依次執行相應的方法,值得注意的是ApplicationContextAware接口的setApplicationContext方法,再看一下invokeInitMethods源碼

1.4.3 InitializingBean接口

在這里插入圖片描述

發現如果實現了InitializingBean接口,重寫了afterPropertiesSet方法,則會調用afterPropertiesSet方法,最后還會調用是否指定了init-method,可以通過標簽,或者@Bean注解的initMethod指定,最后再看一張applyBeanPostProcessorsAfterInitialization源碼圖

1.4.4 BeanPostProcessors接口后置方法

在這里插入圖片描述

發現跟之前的postProcessBeforeInitialization方法類似,也是循環遍歷實現了BeanPostProcessor的接口實現類,執行postProcessAfterInitialization方法。整個bean的生命執行流程就如上面截圖所示,哪個接口的方法在哪里被調用,方法的執行流程。

1.5 bean生命周期總結

最后,對bean的生命流程進行一個流程圖的總結
在這里插入圖片描述
或者看簡單版本:
在這里插入圖片描述

如果有@PostConstruct那么初始化順序為

  • BeanPostProcessorpostProcessBeforeInitialization方法
  • 類中添加了注解@PostConstruct的方法
  • InitializingBeanafterPropertiesSet方法
  • bean的指定的初始化方法: init-method
  • BeanPostProcessorpostProcessAftrInitialization方法

點擊了解bean作用域和線程安全問題

2 重要接口

以下是 spring 容器中 Bean 的生命周期內所有可擴展的點的調用順序,下面會一個個分析
在這里插入圖片描述

2.1 ApplicationContextInitializer

所屬類:org.springframework.context.ApplicationContextInitializer

這是整個spring 容器在刷新之前初始化 ConfigurableApplicationContext 的回調接口,簡單來說,就是在容器刷新之前調用此類的initialize方法。允許被用戶自己擴展。用戶可以在整個spring容器還沒被初始化之前做一些事情。
可以想到的場景可能為,在最開始激活一些配置,或者利用這時候class還沒被類加載器加載的時機,進行動態字節碼注入等操作。

擴展方式為:

public class TestApplicationContextInitializer implements ApplicationContextInitializer {      
    @Override      
    public void initialize(ConfigurableApplicationContext applicationContext) {      
        System.out.println("[ApplicationContextInitializer]");      
    }      
}     

因為這時候spring容器還沒被初始化,所以想要擴展的生效,有以下三種方式:

  • SpringBoot 啟動類中用springApplication.addInitializers(new TestApplicationContextInitializer())語句加入
  • 配置文件配置
    application.properties中添加:context.initializer.classes=com.example.demo.TestApplicationContextInitializer
    或者在application.yml
context:
  initializer:
    classes: com.example.demo.TestApplicationContextInitializer
  • Spring SPI擴展,在 META-INF/services 下的spring.factories中加入org.springframework.context.ApplicationContextInitializer=com.example.demo.TestApplicationContextInitializer

2.2 BeanDefinitionRegistryPostProcessor

所屬類:org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor

這個接口在讀取項目中的 beanDefinition 之后執行,提供一個補充的擴展點
使用場景:可以在這里動態注冊自己的 beanDefinition,可以加載classpath之外的bean

擴展方式為:

public class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {      
    @Override      
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {      
        System.out.println("[BeanDefinitionRegistryPostProcessor] postProcessBeanDefinitionRegistry");      
    }      
      
    @Override      
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {      
        System.out.println("[BeanDefinitionRegistryPostProcessor] postProcessBeanFactory");      
    }      
}      

2.3 BeanFactoryPostProcessor

所屬類:org.springframework.beans.factory.config.BeanFactoryPostProcessor

這個接口是 beanFactory 的擴展接口,調用時機在 spring在讀取beanDefinition信息之后,實例化bean之前。
在這個時機,用戶可以通過實現這個擴展接口來自行處理一些東西,比如修改已經注冊的beanDefinition的元信息。

擴展方式為:

public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {      
    @Override      
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {      
        System.out.println("[BeanFactoryPostProcessor]");      
    }      
}      

2.4 InstantiationAwareBeanPostProcessor

所屬類:org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor

該接口繼承了 BeanPostProcess 接口,區別如下:

  • BeanPostProcess接口只在bean的初始化階段進行擴展(注入spring上下文前后)
  • InstantiationAwareBeanPostProcessor接口在此基礎上增加了3個方法,把可擴展的范圍增加了實例化階段和屬性注入階段。

該類主要的擴展點有以下5個方法,主要在bean生命周期的兩大階段:實例化階段和初始化階段,下面一起進行說明,按調用順序為:

  • postProcessBeforeInstantiation:實例化bean之前,相當於new這個bean之前
  • postProcessAfterInstantiation:實例化bean之后,相當於new這個bean之后
  • postProcessPropertyValues:bean已經實例化完成,在屬性注入時階段觸發,@Autowired,@Resource等注解原理基於此方法實現
  • postProcessBeforeInitialization:初始化bean之前,相當於把bean注入spring上下文之前
  • postProcessAfterInitialization:初始化bean之后,相當於把bean注入spring上下文之后

使用場景:這個擴展點非常有用 ,無論是寫中間件和業務中,都能利用這個特性。比如對實現了某一類接口的bean在各個生命期間進行收集,或者對某個類型的bean進行統一的設值等等。

擴展方式為:

public class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {      
      
    @Override      
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {      
        System.out.println("[TestInstantiationAwareBeanPostProcessor] before initialization " + beanName);      
        return bean;      
    }      
      
    @Override      
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {      
        System.out.println("[TestInstantiationAwareBeanPostProcessor] after initialization " + beanName);      
        return bean;      
    }      
      
    @Override      
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {      
        System.out.println("[TestInstantiationAwareBeanPostProcessor] before instantiation " + beanName);      
        return null;      
    }      
      
    @Override      
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {      
        System.out.println("[TestInstantiationAwareBeanPostProcessor] after instantiation " + beanName);      
        return true;      
    }      
      
    @Override      
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {      
        System.out.println("[TestInstantiationAwareBeanPostProcessor] postProcessPropertyValues " + beanName);      
        return pvs;      
    }      

2.5 SmartInstantiationAwareBeanPostProcessor

所屬類:org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor

該擴展接口有3個觸發點方法:

  • predictBeanType:該觸發點發生在postProcessBeforeInstantiation之前(在圖上並沒有標明,因為一般不太需要擴展這個點),這個方法用於預測Bean的類型,返回第一個預測成功的Class類型,如果不能預測返回null;當你調用BeanFactory.getType(name)時當通過bean的名字無法得到bean類型信息時就調用該回調方法來決定類型信息。
  • determineCandidateConstructors:該觸發點發生在postProcessBeforeInstantiation之后,用於確定該bean的構造函數之用,返回的是該bean的所有構造函數列表。用戶可以擴展這個點,來自定義選擇相應的構造器來實例化這個bean。
  • getEarlyBeanReference:該觸發點發生在postProcessAfterInstantiation之后,當有循環依賴的場景,當bean實例化好之后,為了防止有循環依賴,會提前暴露回調方法,用於bean實例化的后置處理。這個方法就是在提前暴露的回調方法中觸發。

擴展方式為:

public class TestSmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {      
      
    @Override      
    public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {      
        System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] predictBeanType " + beanName);      
        return beanClass;      
    }      
      
    @Override      
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {      
        System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] determineCandidateConstructors " + beanName);      
        return null;      
    }      
      
    @Override      
    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {      
        System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] getEarlyBeanReference " + beanName);      
        return bean;      
    }      
}      

2.6 BeanFactoryAware

所屬類:org.springframework.beans.factory.BeanFactoryAware

這個類只有一個觸發點,發生在bean的實例化之后,注入屬性之前,也就是Setter之前。這個類的擴展點方法為setBeanFactory,可以拿到BeanFactory這個屬性。

使用場景為,你可以在bean實例化之后,但還未初始化之前,拿到 BeanFactory,在這個時候,可以對每個bean作特殊化的定制。也或者可以把BeanFactory拿到進行緩存,日后使用。

擴展方式為:

public class TestBeanFactoryAware implements BeanFactoryAware {      
    @Override      
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {      
        System.out.println("[TestBeanFactoryAware] " + beanFactory.getBean(TestBeanFactoryAware.class).getClass().getSimpleName());      
    }      
}      

2.7 ApplicationContextAwareProcessor

所屬類:org.springframework.context.support.ApplicationContextAwareProcessor

該類本身並沒有擴展點,但是該類內部卻有6個擴展點可供實現 ,這些類觸發的時機在bean實例化之后,初始化之前
在這里插入圖片描述

可以看到,該類用於執行各種驅動接口,在bean實例化之后,屬性填充之后,通過執行以上紅框標出的擴展接口,來獲取對應容器的變量。所以這里應該來說是有6個擴展點,這里就放一起來說了

  • EnvironmentAware:用於獲取EnviromentAware的一個擴展類,這個變量非常有用, 可以獲得系統內的所有參數。當然個人認為這個Aware沒必要去擴展,因為spring內部都可以通過注入的方式來直接獲得。
  • EmbeddedValueResolverAware:用於獲取StringValueResolver的一個擴展類, StringValueResolver用於獲取基於String類型的properties的變量,一般我們都用@Value的方式去獲取,如果實現了這個Aware接口,把StringValueResolver緩存起來,通過這個類去獲取String類型的變量,效果是一樣的。
  • ResourceLoaderAware:用於獲取ResourceLoader的一個擴展類,ResourceLoader可以用於獲取classpath內所有的資源對象,可以擴展此類來拿到ResourceLoader對象。
  • ApplicationEventPublisherAware:用於獲取ApplicationEventPublisher的一個擴展類,ApplicationEventPublisher可以用來發布事件,結合ApplicationListener來共同使用。這個對象也可以通過spring注入的方式來獲得。
  • MessageSourceAware:用於獲取MessageSource的一個擴展類,MessageSource主要用來做國際化。
  • ApplicationContextAware:用來獲取ApplicationContext的一個擴展類,ApplicationContext應該是很多人非常熟悉的一個類了,就是spring上下文管理器,可以手動的獲取任何在spring上下文注冊的bean,我們經常擴展這個接口來緩存spring上下文,包裝成靜態方法。同時ApplicationContext也實現了BeanFactoryMessageSourceApplicationEventPublisher等接口,也可以用來做相關接口的事情。

2.8 BeanNameAware

所屬類:org.springframework.beans.factory.BeanNameAware

可以看到,這個類也是Aware擴展的一種,觸發點在bean的初始化之前,也就是postProcessBeforeInitialization之前,這個類的觸發點方法只有一個:setBeanName
使用場景為:用戶可以擴展這個點,在初始化bean之前拿到spring容器中注冊的的beanName,來自行修改這個beanName的值。

擴展方式為:

public class NormalBeanA implements BeanNameAware{      
    public NormalBeanA() {      
        System.out.println("NormalBean constructor");      
    }      
      
    @Override      
    public void setBeanName(String name) {      
        System.out.println("[BeanNameAware] " + name);      
    }      
}      

2.9 InitializingBean

所屬類:org.springframework.beans.factory.InitializingBean

這個類,顧名思義,也是用來初始化bean的。InitializingBean接口為bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是繼承該接口的類,在初始化bean的時候都會執行該方法。這個擴展點的觸發時機在postProcessAfterInitialization之前。

使用場景:用戶實現此接口,來進行系統啟動的時候一些業務指標的初始化工作。

擴展方式為:

public class NormalBeanA implements InitializingBean{      
    @Override      
    public void afterPropertiesSet() throws Exception {      
        System.out.println("[InitializingBean] NormalBeanA");      
    }      
}      

2.10 FactoryBean

所屬類:org.springframework.beans.factory.FactoryBean

使用場景:用戶可以擴展這個類,來為要實例化的bean作一個代理,比如為該對象的所有的方法作一個攔截,在調用前后輸出一行log,模仿ProxyFactoryBean的功能。
點擊了解 Spring核心之FactoryBean,BeanFactory,ApplicationContext的區別

2.11 SmartInitializingSingleton

所屬類:org.springframework.beans.factory.SmartInitializingSingleton

這個接口中只有一個方法afterSingletonsInstantiated,其作用是是 在spring容器管理的所有單例對象(非懶加載對象)初始化完成之后調用的回調接口。其觸發時機為postProcessAfterInitialization之后。

使用場景:用戶可以擴展此接口在對所有單例對象初始化完畢后,做一些后置的業務處理。

擴展方式為:

public class TestSmartInitializingSingleton implements SmartInitializingSingleton {      
    @Override      
    public void afterSingletonsInstantiated() {      
        System.out.println("[TestSmartInitializingSingleton]");      
    }      
}      

2.12 CommandLineRunner

所屬類:org.springframework.boot.CommandLineRunner

這個接口屬於 SpringBoot 只有一個方法:run(String... args),觸發時機為整個項目啟動完畢后,自動執行。如果有多個CommandLineRunner,可以利用@Order來進行排序。

使用場景:用戶擴展此接口,進行啟動項目之后一些業務的預處理。
擴展方式為:

public class TestCommandLineRunner implements CommandLineRunner {      
      
    @Override      
    public void run(String... args) throws Exception {      
        System.out.println("[TestCommandLineRunner]");      
    }      
}      

2.13 DisposableBean

所屬類:org.springframework.beans.factory.DisposableBean

這個擴展點也只有一個方法:destroy(),其觸發時機為當此對象銷毀時,會自動執行這個方法。比如說運行applicationContext.registerShutdownHook時,就會觸發這個方法。

擴展方式為:

public class NormalBeanA implements DisposableBean {      
    @Override      
    public void destroy() throws Exception {      
        System.out.println("[DisposableBean] NormalBeanA");      
    }      
}      

2.14 ApplicationListener

所屬類:org.springframework.context.ApplicationListener

准確的說,這個應該不算spring&springboot當中的一個擴展點,ApplicationListener可以監聽某個事件的event,觸發時機可以穿插在業務方法執行過程中,用戶可以自定義某個業務事件。
但是spring內部也有一些內置事件,這種事件,可以穿插在啟動調用中。我們也可以利用這個特性,來自己做一些內置事件的監聽器來達到和前面一些觸發點大致相同的事情。

Spring中的事件講解(Application Event)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM