- 1 Bean生命周期
- 2 重要接口
- 2.1 ApplicationContextInitializer
- 2.2 BeanDefinitionRegistryPostProcessor
- 2.3 BeanFactoryPostProcessor
- 2.4 InstantiationAwareBeanPostProcessor
- 2.5 SmartInstantiationAwareBeanPostProcessor
- 2.6 BeanFactoryAware
- 2.7 ApplicationContextAwareProcessor
- 2.8 BeanNameAware
- 2.9 InitializingBean
- 2.10 FactoryBean
- 2.11 SmartInitializingSingleton
- 2.12 CommandLineRunner
- 2.13 DisposableBean
- 2.14 ApplicationListener
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-method
和DisposableBean
接口。
1.2 Bean實例化階段
我們在spring
的BeanFactory
工廠列舉了很多接口,代表着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
大家肯定很好奇,我們是看得懂Spring
中xml
配置文件中一個個的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相關接口
我們可以知道如果我們實現了BeanNameAware
,BeanClassLoaderAware
,BeanFactoryAware
三個Aware
接口的話,會依次調用setBeanName(), setBeanClassLoader(), setBeanFactory()
方法,再看applyBeanPostProcessorsBeforeInitialization
源碼
1.4.2 BeanPostProcessors相關接口
發現會如果有類實現了BeanPostProcessor
接口,就會執行postProcessBeforeInitialization
方法,這里需要注意的是:如果多個類實現BeanPostProcessor
接口,那么多個實現類都會執行postProcessBeforeInitialization
方法,可以看到是for
循環依次執行的,還有一個注意的點就是如果加載A類到spring
容器中,A類也重寫了BeanPostProcessor
接口的postProcessBeforeInitialization
方法,這時要注意A類的postProcessBeforeInitialization
方法並不會得到執行,因為A類還未加載完成,還未完全放到spring
的singletonObjects
一級緩存中。
再看一個注意的點
可以看到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
那么初始化順序為
BeanPostProcessor
的postProcessBeforeInitialization
方法- 類中添加了注解
@PostConstruct
的方法 InitializingBean
的afterPropertiesSet
方法bean
的指定的初始化方法:init-method
BeanPostProcessor
的postProcessAftrInitialization
方法
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
也實現了BeanFactory
,MessageSource
,ApplicationEventPublisher
等接口,也可以用來做相關接口的事情。
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
內部也有一些內置事件,這種事件,可以穿插在啟動調用中。我們也可以利用這個特性,來自己做一些內置事件的監聽器來達到和前面一些觸發點大致相同的事情。