Spring作為當前Java最流行、最強大的輕量級框架,Spring Bean的生命周期也是面試高頻題,了解Spring Bean周期也能更好地幫助我們解決日常開發中的問題,程式員應該都知道Spring的基礎容器是ApplicationContext,應很多粉絲的強烈建議,本文我來分析分析 ApplicationContext中Bean的生命周期,ApplicationContext是頂層容器介面BeanFactory的實作類,因此,我們了解了ApplicationContext的生命周期邏輯,也基本上了解了其他型別容器的生命周期邏輯,
1 Spring生命周期流程圖
下面先來看一張Spring Bean完整的生命周期流程圖,下圖描述的是從Spring容器初始化Bean開始直到Spring容器銷毀Bean,所經歷的關鍵節點,

從上圖可以看出,Spring Bean的生命周期管理的基本思路是:在Bean出現之前,先準備操作Bean的BeanFactory,然后操作完Bean,所有的Bean也還會交給BeanFactory進行管理,在所有Bean操作準備BeanPostProcessor作為回呼,在Bean的完整生命周期管理程序中,經歷了以下主要幾個步驟:
1.1 Bean創建前的準備階段
步驟1: Bean容器在組態檔中找到Spring Bean的定義以及相關的配置,如init-method和destroy-method指定的方法,
步驟2: 實體化回呼相關的后置處理器如BeanFactoryPostProcessor、BeanPostProcessor、InstantiationAwareBeanPostProcessor等
1.2 創建Bean的實體
步驟3: Srping 容器使用Java反射API創建Bean的實體,
步驟4:掃描Bean宣告的屬性并決議,
1.3 開始依賴注入
步驟5:開始依賴注入,決議所有需要賦值的屬性并賦值,
步驟6:如果Bean類實作BeanNameAware介面,則將通過傳遞Bean的名稱來呼叫setBeanName()方法,
步驟7:如果Bean類實作BeanFactoryAware介面,則將通過傳遞BeanFactory物件的實體來呼叫setBeanFactory()方法,
步驟8:如果有任何與BeanFactory關聯的BeanPostProcessors物件已加載Bean,則將在設定Bean屬性之前呼叫postProcessBeforeInitialization()方法,
步驟9:如果Bean類實作了InitializingBean介面,則在設定了組態檔中定義的所有Bean屬性后,將呼叫afterPropertiesSet()方法,
1.4 快取到Spring容器
步驟10: 如果組態檔中的Bean定義包含init-method屬性,則該屬性的值將決議為Bean類中的方法名稱,并將呼叫該方法,
步驟11:如果為Bean Factory物件附加了任何Bean 后置處理器,則將呼叫postProcessAfterInitialization()方法,
1.5 銷毀Bean的實體
步驟12:如果Bean類實作DisposableBean介面,則當Application不再需要Bean參考時,將呼叫destroy()方法,
步驟13:如果組態檔中的Bean定義包含destroy-method屬性,那么將呼叫Bean類中的相應方法定義,
2 代碼實戰演示
下面我們用一個簡單的Bean來演示并觀察一下Spring Bean完整的生命周期,
2.1 準備Author類
1、首先是一個簡單的Bean,呼叫Bean自身的方法和Bean級生命周期介面方法,為了方便演示,它實作了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean這4個介面,同時添加2個init-method和destory-method方法,對應組態檔中
package com.tom.lifecycle;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
@Slf4j
@Data
public class Author implements BeanFactoryAware, BeanNameAware, InitializingBean, DisposableBean {
private String name;
private String address;
private int age;
private BeanFactory beanFactory;
private String beanName;
public Author() {
log.info("【構造器】呼叫Tom類的構造器實體化");
}
public void setName(String name) {
log.info("【注入屬性】name");
this.name = name;
}
public void setAddress(String address) {
log.info("【注入屬性】address");
this.address = address;
}
public void setAge(int age) {
log.info("【注入屬性】age");
this.age = age;
}
// 實作BeanFactoryAware介面的方法
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
log.info("【BeanFactoryAware介面】呼叫setBeanFactory方法");
this.beanFactory = beanFactory;
}
// 實作BeanNameAware介面的方法
public void setBeanName(String beanName) {
log.info("【BeanNameAware介面】呼叫setBeanName方法");
this.beanName = beanName;
}
// 實作DiposibleBean介面的方法
public void destroy() throws Exception {
log.info("【DiposibleBean介面】呼叫destroy方法");
}
// 實作InitializingBean介面的方法
public void afterPropertiesSet() throws Exception {
log.info("【InitializingBean介面】呼叫afterPropertiesSet方法");
}
// 通過<bean>的init-method屬性指定的初始化方法
public void beanInit() {
log.info("【init-method】呼叫<bean>的init-method屬性指定的初始化方法");
}
// 通過<bean>的destroy-method屬性指定的初始化方法
public void beanDestory() {
log.info("【destroy-method】呼叫<bean>的destroy-method屬性指定的初始化方法");
}
}
在配置Spring組態檔中加入如下內容:
<bean id="author"
init-method="beanInit"
destroy-method="beanDestory"
scope="singleton"
p:name="Tom" p:address="湖南長沙" p:age="18"/>
2.2 演示BeanFactoryPostProcessor的執行
1.創建GPBeanFactoryPostProcessor類,并實作BeanFactoryPostProcessor介面,具體代碼如下:
package com.tom.lifecycle;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
@Slf4j
public class GPBeanFactoryPostProcessor implements BeanFactoryPostProcessor{
public GPBeanFactoryPostProcessor() {
super();
log.info("呼叫BeanFactoryPostProcessor實作類構造器!!");
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
log.info("BeanFactoryPostProcessor呼叫postProcessBeanFactory方法");
BeanDefinition bd = configurableListableBeanFactory.getBeanDefinition("author");
bd.getPropertyValues().addPropertyValue("age", "16");
}
}
2.在配置Spring組態檔中加入如下內容:
<bean id="beanFactoryPostProcessor" />
3.撰寫測驗類BeanLifeCycleTest,具體代碼如下:
package com.tom.lifecycle;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@Slf4j
public class BeanLifeCycleTest {
public static void main(String[] args) {
log.info("====== 開始初始化Spring容器 ========");
ApplicationContext factory = new ClassPathXmlApplicationContext("application-beans.xml");
log.info("====== 初始化Spring容器成功 ========");
//獲取Author實體
Author author = factory.getBean("author", Author.class);
log.info(author.toString());
log.info("====== 開始銷毀Spring容器 ========");
((ClassPathXmlApplicationContext) factory).registerShutdownHook();
}
}
4.運行結果
運行結果如下:
15:49:12.477 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - 呼叫BeanPostProcessor實作類構造器!!
15:49:12.494 [main] INFO com.tom.lifecycle.Author - 【構造器】呼叫Tom類的構造器實體化
15:49:12.527 [main] INFO com.tom.lifecycle.Author - 【注入屬性】address
15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【注入屬性】age
15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【注入屬性】name
15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【BeanNameAware介面】呼叫setBeanName方法
15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【BeanFactoryAware介面】呼叫setBeanFactory方法
15:49:12.528 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - BeanPostProcessor介面方法postProcessBeforeInitialization對屬性進行更改
15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【InitializingBean介面】呼叫afterPropertiesSet方法
15:49:12.528 [main] INFO com.tom.lifecycle.Author - 【init-method】呼叫<bean>的init-method屬性指定的初始化方法
15:49:12.528 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - BeanPostProcessor介面方法postProcessAfterInitialization對屬性進行更改
15:49:12.531 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - ====== 初始化Spring容器成功 ========
15:49:12.531 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - Author(name=Tom, address=湖南長沙, age=18, beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory@26653222: defining beans [beanPostProcessor,author]; root of factory hierarchy, beanName=author)
15:49:12.531 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - ====== 開始銷毀Spring容器 ========
15:49:12.532 [Thread-0] INFO com.tom.lifecycle.Author - 【DiposibleBean介面】呼叫destroy方法
15:49:12.533 [Thread-0] INFO com.tom.lifecycle.Author - 【destroy-method】呼叫<bean>的destroy-method屬性指定的初始化方法
我們看到,整個執行和我們一開始繪制的流程圖一致,但是為什么我們要實作BeanFactoryPostProcessor介面呢?我們進入到BeanFactoryPostProcessor的原始碼如下:
package org.springframework.beans.factory.config;
import org.springframework.beans.BeansException;
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
}
BeanFactoryPostProcessor介面只有一個postProcessBeanFactory()方法,BeanFactoryPostProcessor:在BeanFactory標準初始化之后可以進行修改,將加載所有Bean定義,但是還沒有實體化Bean,這個方法允許重新覆寫或者添加屬性甚至快速的初始化bean,初次看到可能不知道postProcessBeanFactory()到底是干嘛的,要想透徹理解這個方法的作用,下面來進入到BeanFactoryPostProcessor的原始碼,理解一下postProcessBeanFactory()的引數,我們可以利用這些引數做一些操作,
通過引數來看,只有一個ConfigurableListableBeanFactory類,這個類的可以提供分析、修改Bean定義和預先實體化單例的功能,我們再進入到ConfigurableListableBeanFactory的原始碼中:
public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
//忽略被給定注入依賴型別 ,例如String
void ignoreDependencyType(Class<?> var1);
//略被給定注入依賴介面 ,這個通常被使用由ApplicationContext去注冊依賴,可以以多種方式實作,例如BeanFactory通過BeanFactoryAware,ApplicationContext 通過ApplicationContextAware,默認情況下,僅BeanFactoryAware介面是被忽略,需要忽略其他介面,呼叫此方法
void ignoreDependencyInterface(Class<?> var1);
//注冊一個特定型別依賴伴隨著相應的Autowired值,這個是準備被用于應該可以Autowire而不是在這個工廠被定義的Bean的工廠/背景關系參考,例如 將ApplicationContext型別的依賴項決議為Bean所在的ApplicationContext實體,注意~在普通的BeanFactory中沒有注冊這樣的默認型別,甚至連BeanFactory介面本身都沒有
void registerResolvableDependency(Class<?> var1, Object var2);
//確認這個被指定的Bean是否是一個Autowire候選,將被注入到其他宣告匹配型別的依賴的Bean中
boolean isAutowireCandidate(String var1, DependencyDescriptor var2) throws NoSuchBeanDefinitionException;
//根據指定的beanName回傳被注冊的Bean定義,允許訪問其屬性值和建構式引數值(可以在BeanFactory后期處理期間被修改),這個被回傳的BeanDefinition物件不應該是副本而是原始在工廠被注冊的,這意味著如果需要它可以被轉換為更具體的實作型別,注意這個方法只能獲得本地工廠BeanDefinition
BeanDefinition getBeanDefinition(String var1) throws NoSuchBeanDefinitionException;
//凍結全部Bean定義,給被注冊的Bean定義發信號告訴它們今后不再被修改和進一步后續處理,它允許Factory去積極快取Bean定義元資料
void freezeConfiguration();
//回傳該工廠的BeanDefinnition是否被凍結
boolean isConfigurationFrozen();
//確保所有非懶加載的單例Bean被實體化,包括FactoryBean
void preInstantiateSingletons() throws BeansException;
}
通過以上演示和分析,我們應該大概能夠了解ConfigurableListableBeanFactory的作用,基本就都是對于Bean定義的操作,至此我們還沒有看到BeanPostProcessor 和InstantiationAwareBeanPostProcessor的呼叫,下面我們把BeanPostProcessor 和InstantiationAwareBeanPostProcessor的實作補充上來,再看完整的執行流程
2.3 實作BeanPostProcessor
創建GPBeanPostProcessor類,并實作BeanPostProcessor 介面,具體代碼如下:
package com.tom.lifecycle;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
@Slf4j
public class GPBeanPostProcessor implements BeanPostProcessor {
public GPBeanPostProcessor(){
log.info("呼叫BeanPostProcessor實作類構造器!!");
}
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
log.info("BeanPostProcessor介面方法postProcessBeforeInitialization對屬性進行更改");
return o;
}
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
log.info("BeanPostProcessor介面方法postProcessAfterInitialization對屬性進行更改");
return o;
}
}
ApplicationContext 可以在BeanDefinition中自動檢測到實作了BeanPostProcessor的Bean,并且把這些Bean應用于隨后的Bean創建,普通的BeanFactory允許對后處理器進行程式化注冊,通過工廠應用于所有Bean創建,BeanPostProcessor介面中主要有兩個方法:
| 方法名 | 解釋 |
|---|---|
| postProcessBeforeInitialization | 在Bean實體化回呼(例如InitializingBean的afterPropertiesSet 或者一個定制的init-method)之前應用此BeanPostProcessor |
| postProcessAfterInitialization | 在bean實體化回呼(例如InitializingBean的afterPropertiesSet 或者一個定制的init-method)之后應用此BeanPostProcessor |
2.4 實作InstantiationAwareBeanPostProcessor
創建GPInstantiationAwareBeanPostProcessor類,并實作InstantiationAwareBeanPostProcessorAdapter介面,具體代碼如下:
package com.tom.lifecycle;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import java.beans.PropertyDescriptor;
@Slf4j
public class GPInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
public GPInstantiationAwareBeanPostProcessor() {
super();
log.info("呼叫InstantiationAwareBeanPostProcessorAdapter實作類構造器!!");
}
// 介面方法、實體化Bean之前呼叫
@Override
public Object postProcessBeforeInstantiation(Class beanClass,String beanName) throws BeansException {
log.info("InstantiationAwareBeanPostProcessor呼叫postProcessBeforeInstantiation方法");
return null;
}
// 介面方法、實體化Bean之后呼叫
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
log.info("InstantiationAwareBeanPostProcessor呼叫postProcessAfterInitialization方法");
return bean;
}
// 介面方法、設定某個屬性時呼叫
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
log.info("InstantiationAwareBeanPostProcessor呼叫postProcessPropertyValues方法");
return pvs;
}
}
實作InstantiationAwareBeanPostProcessorAdapter的Bean之后,可以在實體化成功之后,做一些校驗或者補充些內容或者把Bean包裝代理注入,實作InstantiationAwareBeanPostProcessorAdapter的Bean之后,不會影響容器正常處理每一個實體化的Bean,其子類僅僅只是根據需要覆寫父類的方法,
注意,只有在實際需要 InstantiationAwareBeanPostProcessor 功能時才推薦此基類,如果我們所需要的只是簡單的BeanPostProcessor功能,那么直接實作更簡單的介面即可,
下面詳細介紹一下InstantiationAwareBeanPostProcessorAdapter介面中的所有方法:
| 方法名 | 解釋 |
|---|---|
| postProcessBeforeInstantiation | 在實體化目標Bean之前應用此BeanPostProcessor,這個回傳的Bean也許是一個代理代替目標Bean,有效地抑制目標Bean的默認實體化,如果此方法回傳一個非空物件,則Bean的創建程序將被短路,唯一的進一步處理被應用是BeanPostProcessor.postProcessAfterInitialization(java.lang.Object, java.lang.String)方法(改變了Bean的生命周期實體化之后直接進入BeanPostProcessor.postProcessAfterInitialization)回呼來自于配置好的BeanPostProcessors,這個回呼將僅被應用于有Bean Class的BeanDefintions,特別是,它不會應用于采用”factory-method“的Bean,后處理器可以實作擴展的SmartInstantiationAwareBeanPostProcessor介面,以便預測它們將回傳的Bean物件的型別 |
| postProcessPropertyValues | 在工廠將給定的屬性值應用到給定的Bean之前,對給定的屬性值進行后處理,允許檢查全部依賴是否已經全部滿足,例如基于一個@Required在Bean屬性的Setter方法上,還允許替換要應用的屬性值,通常通過基于原始的PropertyValues創建一個新的MutablePropertyValues實體,添加或洗掉特定的值 |
| postProcessAfterInitialization | 在Bean初始化回呼(如InitializingBean的afterPropertiesSet或者定制的init-method)之后,應用這個BeanPostProcessor去給一個新的Bean實體,Bean已經配置了屬性值,回傳的Bean實體可能已經被包裝, 如果是FactoryBean,這個回呼將為FactoryBean實體和其他被FactoryBean創建的物件所呼叫,這個post-processor可以通過相應的FactoryBean實體去檢查決定是否應用FactoryBean或者被創建的物件或者兩個都有,這個回呼在一個由InstantiationAwareBeanPostProcessor短路的觸發之后將被呼叫 |
2.5 修改組態檔
完整的組態檔內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<bean id="beanPostProcessor" />
<bean id="beanFactoryPostProcessor" />
<bean id="instantiationAwareBeanPostProcessor" />
<bean id="author"
init-method="beanInit"
destroy-method="beanDestory"
scope="singleton"
p:name="Tom" p:address="湖南長沙" p:age="18"/>
</beans>
2.6 運行結果
最后,我們再次運行BeanLifeCycleTest測驗類,看到如下運行結果:
15:56:20.030 [main] INFO com.tom.lifecycle.GPBeanFactoryPostProcessor - 呼叫BeanFactoryPostProcessor實作類構造器!!
15:56:20.045 [main] INFO com.tom.lifecycle.GPBeanFactoryPostProcessor - BeanFactoryPostProcessor呼叫postProcessBeanFactory方法
15:56:20.046 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - 呼叫BeanPostProcessor實作類構造器!!
15:56:20.047 [main] INFO com.tom.lifecycle.GPInstantiationAwareBeanPostProcessor - 呼叫InstantiationAwareBeanPostProcessorAdapter實作類構造器!!
15:56:20.051 [main] INFO com.tom.lifecycle.GPInstantiationAwareBeanPostProcessor - InstantiationAwareBeanPostProcessor呼叫postProcessBeforeInstantiation方法
15:56:20.052 [main] INFO com.tom.lifecycle.Author - 【構造器】呼叫Tom類的構造器實體化
15:56:20.069 [main] INFO com.tom.lifecycle.GPInstantiationAwareBeanPostProcessor - InstantiationAwareBeanPostProcessor呼叫postProcessPropertyValues方法
15:56:20.092 [main] INFO com.tom.lifecycle.Author - 【注入屬性】address
15:56:20.092 [main] INFO com.tom.lifecycle.Author - 【注入屬性】age
15:56:20.092 [main] INFO com.tom.lifecycle.Author - 【注入屬性】name
15:56:20.092 [main] INFO com.tom.lifecycle.Author - 【BeanNameAware介面】呼叫setBeanName方法
15:56:20.092 [main] INFO com.tom.lifecycle.Author - 【BeanFactoryAware介面】呼叫setBeanFactory方法
15:56:20.093 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - BeanPostProcessor介面方法postProcessBeforeInitialization對屬性進行更改
15:56:20.093 [main] INFO com.tom.lifecycle.Author - 【InitializingBean介面】呼叫afterPropertiesSet方法
15:56:20.093 [main] INFO com.tom.lifecycle.Author - 【init-method】呼叫<bean>的init-method屬性指定的初始化方法
15:56:20.093 [main] INFO com.tom.lifecycle.GPBeanPostProcessor - BeanPostProcessor介面方法postProcessAfterInitialization對屬性進行更改
15:56:20.093 [main] INFO com.tom.lifecycle.GPInstantiationAwareBeanPostProcessor - InstantiationAwareBeanPostProcessor呼叫postProcessAfterInitialization方法
15:56:20.097 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - ====== 初始化Spring容器成功 ========
15:56:20.098 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - Author(name=Tom, address=湖南長沙, age=16, beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory@26653222: defining beans [beanPostProcessor,beanFactoryPostProcessor,instantiationAwareBeanPostProcessor,author]; root of factory hierarchy, beanName=author)
15:56:20.098 [main] INFO com.tom.lifecycle.BeanLifeCycleTest - ====== 開始銷毀Spring容器 ========
15:56:20.099 [Thread-0] INFO com.tom.lifecycle.Author - 【DiposibleBean介面】呼叫destroy方法
15:56:20.100 [Thread-0] INFO com.tom.lifecycle.Author - 【destroy-method】呼叫<bean>的destroy-method屬性指定的初始化方法
3 Spring Bean生命周期運行時序圖
最后我們來看一下完整的執行時序圖:

關注微信公眾號『 Tom彈架構 』回復“Spring”可獲取完整原始碼,
本文為“Tom彈架構”原創,轉載請注明出處,技術在于分享,我分享我快樂!
如果本文對您有幫助,歡迎關注和點贊;如果您有任何建議也可留言評論或私信,您的支持是我堅持創作的動力,關注微信公眾號『 Tom彈架構 』可獲取更多技術干貨!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/376832.html
標籤:Java
