在分析 Spring Bean 實(shí)例化過程中提到 Spring 并不是一啟動(dòng)容器就開啟 bean 的實(shí)例化進(jìn)程,只有當(dāng)客戶端通過顯示或者隱式的方式調(diào)用 BeanFactory 的 getBean() 方法來請(qǐng)求某個(gè)實(shí)例對(duì)象的時(shí)候,它才會(huì)觸發(fā)相應(yīng) bean 的實(shí)例化進(jìn)程,當(dāng)然也可以選擇直接使用 ApplicationContext 容器,因?yàn)樵撊萜鲉?dòng)的時(shí)候會(huì)立刻調(diào)用注冊(cè)到該容器所有 bean 定義的實(shí)例化方法。當(dāng)然對(duì)于 BeanFactory 容器而言并不是所有的 getBean() 方法都會(huì)觸發(fā)實(shí)例化進(jìn)程,比如 signleton 類型的 bean,該類型的 bean 只會(huì)在第一次調(diào)用 getBean() 的時(shí)候才會(huì)觸發(fā),而后續(xù)的調(diào)用則會(huì)直接返回容器緩存中的實(shí)例對(duì)象。
getBean() 只是 bean 實(shí)例化進(jìn)程的入口,真正的實(shí)現(xiàn)邏輯其實(shí)是在 AbstractAutowireCapableBeanFactory 的 doCreateBean() 實(shí)現(xiàn),實(shí)例化過程如下圖:

原來我們采用 new 的方式創(chuàng)建一個(gè)對(duì)象,用完該對(duì)象在其脫離作用域后就會(huì)被回收,對(duì)于后續(xù)操作我們無權(quán)也沒法干涉,但是采用 Spring 容器后,我們完全擺脫了這種命運(yùn),Spring 容器將會(huì)對(duì)其所有管理的 Bean 對(duì)象全部給予一個(gè)統(tǒng)一的生命周期管理,同時(shí)在這個(gè)階段我們也可以對(duì)其進(jìn)行干涉(比如對(duì) bean 進(jìn)行增強(qiáng)處理,對(duì) bean 進(jìn)行篡改),如上圖。
bean 實(shí)例化
在 doCreateBean() 中首先進(jìn)行 bean 實(shí)例化工作,主要由 createBeanInstance() 實(shí)現(xiàn),該方法返回一個(gè) BeanWrapper 對(duì)象。BeanWrapper 對(duì)象是 Spring 的一個(gè)低級(jí) Bean 基礎(chǔ)結(jié)構(gòu)的核心接口,為什么說是低級(jí)呢?因?yàn)檫@個(gè)時(shí)候的 Bean 還不能夠被我們使用,連最基本的屬性都沒有設(shè)置。而且在我們實(shí)際開發(fā)過程中一般都不會(huì)直接使用該類,而是通過 BeanFactory 隱式使用。
BeanWrapper 接口有一個(gè)默認(rèn)實(shí)現(xiàn)類 BeanWrapperImpl,其主要作用是對(duì) Bean 進(jìn)行“包裹”,然后對(duì)這個(gè)包裹的 bean 進(jìn)行操作,比如后續(xù)注入 bean 屬性。
在實(shí)例化 bean 過程中,Spring 采用“策略模式”來決定采用哪種方式來實(shí)例化 bean,一般有反射和 CGLIB 動(dòng)態(tài)字節(jié)碼兩種方式。
InstantiationStrategy 定義了 Bean 實(shí)例化策略的抽象接口,其子類 SimpleInstantiationStrategy 提供了基于反射來實(shí)例化對(duì)象的功能,但是不支持方法注入方式的對(duì)象實(shí)例化。CglibSubclassingInstantiationStrategy 繼承 SimpleInstantiationStrategy,他除了擁有父類以反射實(shí)例化對(duì)象的功能外,還提供了通過 CGLIB 的動(dòng)態(tài)字節(jié)碼的功能進(jìn)而支持方法注入所需的對(duì)象實(shí)例化需求。默認(rèn)情況下,Spring 采用 CglibSubclassingInstantiationStrategy。
激活 Aware
當(dāng) Spring 完成 bean 對(duì)象實(shí)例化并且設(shè)置完相關(guān)屬性和依賴后,則會(huì)開始 bean 的初始化進(jìn)程(initializeBean()),初始化第一個(gè)階段是檢查當(dāng)前 bean 對(duì)象是否實(shí)現(xiàn)了一系列以 Aware 結(jié)尾的的接口。
Aware 接口為 Spring 容器的核心接口,是一個(gè)具有標(biāo)識(shí)作用的超級(jí)接口,實(shí)現(xiàn)了該接口的 bean 是具有被 Spring 容器通知的能力,通知的方式是采用回調(diào)的方式。
在初始化階段主要是感知 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware :
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
BeanNameAware:對(duì)該 bean 對(duì)象定義的 beanName 設(shè)置到當(dāng)前對(duì)象實(shí)例中
BeanClassLoaderAware:將當(dāng)前 bean 對(duì)象相應(yīng)的 ClassLoader 注入到當(dāng)前對(duì)象實(shí)例中
BeanFactoryAware:BeanFactory 容器會(huì)將自身注入到當(dāng)前對(duì)象實(shí)例中,這樣當(dāng)前對(duì)象就會(huì)擁有一個(gè) BeanFactory 容器的引用。
當(dāng)然,Spring 不僅僅只是提供了上面三個(gè) Aware 接口,而是一系列:
- LoadTimeWeaverAware:加載Spring Bean時(shí)織入第三方模塊,如AspectJ
- BootstrapContextAware:資源適配器BootstrapContext,如JCA,CCI
- ResourceLoaderAware:底層訪問資源的加載器
- PortletConfigAware:PortletConfig
- PortletContextAware:PortletContext
- ServletConfigAware:ServletConfig
- ServletContextAware:ServletContext
- MessageSourceAware:國際化
- ApplicationEventPublisherAware:應(yīng)用事件
- NotificationPublisherAware:JMX通知
BeanPostProcessor
初始化第二個(gè)階段則是 BeanPostProcessor 增強(qiáng)處理,在該階段 BeanPostProcessor 會(huì)處理當(dāng)前容器內(nèi)所有符合條件的實(shí)例化后的 bean 對(duì)象。它主要是對(duì) Spring 容器提供的 bean 實(shí)例對(duì)象進(jìn)行有效的擴(kuò)展,允許 Spring 在初始化 bean 階段對(duì)其進(jìn)行定制化修改,如處理標(biāo)記接口或者為其提供代理實(shí)現(xiàn)。
BeanPostProcessor 接口提供了兩個(gè)方法,在不同的時(shí)機(jī)執(zhí)行,分別對(duì)應(yīng)上圖的前置處理和后置處理。
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
InitializingBean 和 init-method
InitializingBean 是一個(gè)接口,它為 Spring Bean 的初始化提供了一種方式,它有一個(gè) afterPropertiesSet() 方法,在 bean 的初始化進(jìn)程中會(huì)判斷當(dāng)前 bean 是否實(shí)現(xiàn)了 InitializingBean,如果實(shí)現(xiàn)了則調(diào)用 afterPropertiesSet() 進(jìn)行初始化工作。然后再檢查是否也指定了 init-method(),如果指定了則通過反射機(jī)制調(diào)用指定的 init-method()。
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
Boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}
, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
} else {
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
對(duì)于 Spring 而言,雖然上面兩種方式都可以實(shí)現(xiàn)初始化定制化,但是更加推崇 init-method 方式,因?yàn)閷?duì)于 InitializingBean 接口而言,他需要 bean 去實(shí)現(xiàn)接口,這樣就會(huì)污染我們的應(yīng)用程序,顯得 Spring 具有一定的侵入性。但是由于 init-method 是采用反射的方式,所以執(zhí)行效率上相對(duì)于 InitializingBean 接口回調(diào)的方式可能會(huì)低一些。
DisposableBean 和 destroy-method
與 InitializingBean 和 init-method 用于對(duì)象的自定義初始化工作相似,DisposableBean和 destroy-method 則用于對(duì)象的自定義銷毀工作。
當(dāng)一個(gè) bean 對(duì)象經(jīng)歷了實(shí)例化、設(shè)置屬性、初始化階段,那么該 bean 對(duì)象就可以供容器使用了(調(diào)用的過程)。當(dāng)完成調(diào)用后,如果是 singleton 類型的 bean ,則會(huì)看當(dāng)前 bean 是否應(yīng)實(shí)現(xiàn)了 DisposableBean 接口或者配置了 destroy-method 屬性,如果是的話,則會(huì)為該實(shí)例注冊(cè)一個(gè)用于對(duì)象銷毀的回調(diào)方法,便于在這些 singleton 類型的 bean 對(duì)象銷毀之前執(zhí)行銷毀邏輯。
但是,并不是對(duì)象完成調(diào)用后就會(huì)立刻執(zhí)行銷毀方法,因?yàn)檫@個(gè)時(shí)候 Spring 容器還處于運(yùn)行階段,只有當(dāng) Spring 容器關(guān)閉的時(shí)候才會(huì)去調(diào)用。但是, Spring 容器不會(huì)這么聰明會(huì)自動(dòng)去調(diào)用這些銷毀方法,而是需要我們主動(dòng)去告知 Spring 容器。
- 對(duì)于 BeanFactory 容器而言,我們需要主動(dòng)調(diào)用 destroySingletons() 通知 BeanFactory 容器去執(zhí)行相應(yīng)的銷毀方法。
- 對(duì)于 ApplicationContext 容器而言調(diào)用 registerShutdownHook() 方法。
實(shí)踐驗(yàn)證
下面用一個(gè)實(shí)例來真實(shí)看看看上面執(zhí)行的邏輯,畢竟理論是不能缺少實(shí)踐的:
public class lifeCycleBean implements BeanNameAware,BeanFactoryAware,BeanClassLoaderAware,BeanPostProcessor,
InitializingBean,DisposableBean {
private String test;
public String getTest() {
return test;
}
public void setTest(String test) {
System.out.println("屬性注入....");
this.test = test;
}
public lifeCycleBean(){
System.out.println("構(gòu)造函數(shù)調(diào)用...");
}
public void display(){
System.out.println("方法調(diào)用...");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryAware 被調(diào)用...");
}
@Override
public void setBeanName(String name) {
System.out.println("BeanNameAware 被調(diào)用...");
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("BeanClassLoaderAware 被調(diào)用...");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor postProcessBeforeInitialization 被調(diào)用...");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor postProcessAfterInitialization 被調(diào)用...");
return bean;
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean destroy 被調(diào)動(dòng)...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean afterPropertiesSet 被調(diào)動(dòng)...");
}
public void initMethod(){
System.out.println("init-method 被調(diào)用...");
}
public void destroyMethdo(){
System.out.println("destroy-method 被調(diào)用...");
}
}
lifeCycleBean 繼承了 BeanNameAware , BeanFactoryAware , BeanClassLoaderAware , BeanPostProcessor ,
InitializingBean , DisposableBean 六個(gè)接口,同時(shí)定義了一個(gè) test 屬性用于驗(yàn)證屬性注入和提供一個(gè) display() 用于模擬調(diào)用。 配置如下:
<bean id="lifeCycle" class="org.springframework.core.test.lifeCycleBean"
init-method="initMethod" destroy-method="destroyMethdo">
<property name="test" value="test"/>
</bean>
配置 init-method 和 destroy-method。測(cè)試方法如下:
// BeanFactory 容器一定要調(diào)用該方法進(jìn)行 BeanPostProcessor 注冊(cè)
factory.addBeanPostProcessor(new lifeCycleBean());
lifeCycleBean lifeCycleBean = (lifeCycleBean) factory.getBean("lifeCycle");
lifeCycleBean.display();
System.out.println("方法調(diào)用完成,容器開始關(guān)閉....");
// 關(guān)閉容器
factory.destroySingletons();
運(yùn)行結(jié)果:
構(gòu)造函數(shù)調(diào)用...
構(gòu)造函數(shù)調(diào)用...
屬性注入....
BeanNameAware 被調(diào)用...
BeanClassLoaderAware 被調(diào)用...
BeanFactoryAware 被調(diào)用...
BeanPostProcessor postProcessBeforeInitialization 被調(diào)用...
InitializingBean afterPropertiesSet 被調(diào)動(dòng)...
init-method 被調(diào)用...
BeanPostProcessor postProcessAfterInitialization 被調(diào)用...
方法調(diào)用...
方法調(diào)用完成,容器開始關(guān)閉....
DisposableBean destroy 被調(diào)動(dòng)...
destroy-method 被調(diào)用...
有兩個(gè)構(gòu)造函數(shù)調(diào)用是因?yàn)橐⑷胍粋€(gè) BeanPostProcessor(你也可以另外提供一個(gè) BeanPostProcessor 實(shí)例)。
根據(jù)執(zhí)行的結(jié)果已經(jīng)上面的分析,我們就可以對(duì) Spring Bean 的聲明周期過程如下(方法級(jí)別):
- Spring 容器根據(jù)實(shí)例化策略對(duì) Bean 進(jìn)行實(shí)例化。
- 實(shí)例化完成后,如果該 bean 設(shè)置了一些屬性的話,則利用 set 方法設(shè)置一些屬性。
- 如果該 Bean 實(shí)現(xiàn)了 BeanNameAware 接口,則調(diào)用 setBeanName() 方法。
- 如果該 bean 實(shí)現(xiàn)了 BeanClassLoaderAware 接口,則調(diào)用 setBeanClassLoader() 方法。
- 如果該 bean 實(shí)現(xiàn)了 BeanFactoryAware接口,則調(diào)用 setBeanFactory() 方法。
- 如果該容器注冊(cè)了 BeanPostProcessor,則會(huì)調(diào)用postProcessBeforeInitialization() 方法完成 bean 前置處理
- 如果該 bean 實(shí)現(xiàn)了 InitializingBean 接口,則調(diào)用 。afterPropertiesSet() 方法。
- 如果該 bean 配置了 init-method 方法,則調(diào)用 init-method 指定的方法。
- 初始化完成后,如果該容器注冊(cè)了 BeanPostProcessor 則會(huì)調(diào)用 postProcessAfterInitialization() 方法完成 bean 的后置處理。
- 對(duì)象完成初始化,開始方法調(diào)用。
- 在容器進(jìn)行關(guān)閉之前,如果該 bean 實(shí)現(xiàn)了 DisposableBean 接口,則調(diào)用 destroy() 方法。
- 在容器進(jìn)行關(guān)閉之前,如果該 bean 配置了 destroy-mehod,則調(diào)用其指定的方法。
- 到這里一個(gè) bean 也就完成了它的一生。