前言
本篇文章主要是要介紹如何在Spring IoC 容器中 如何管理Spring Bean生命周期。
在應用開發中,常常需要執行一些特定的初始化工作,這些工作都是相對比較固定的,比如建立數據庫連接,打開網絡連接等,同時,在結束服務時,也有一些相對固定的銷毀工作需要執行。為了便于這些工作的設計,Spring IoC容器提供了相關的功能,可以讓應用定制Bean的初始化和銷毀過程。
Spring Bean 生命周期
圖片描述
先來看看 Spring Bean 的生命周期流程圖。結合圖看后面的描述會更輕松一點哦。
文字描述
- Bean容器在配置文件中找到Spring Bean的定義。
- Bean容器使用Java Reflection API創建Bean的實例。
- 如果聲明了任何屬性,聲明的屬性會被設置。如果屬性本身是Bean,則將對其進行解析和設置。
- 如果Bean類實現
BeanNameAware
接口,則將通過傳遞Bean的名稱來調用setBeanName()
方法。 - 如果Bean類實現
BeanClassLoaderAware
接口,則將通過傳遞加載此Bean的ClassLoader對象的實例來調用setBeanClassLoader()
方法。 - 如果Bean類實現
BeanFactoryAware
接口,則將通過傳遞BeanFactory對象的實例來調用setBeanFactory()
方法。 - 如果有任何與BeanFactory關聯的BeanPostProcessors對象已加載Bean,則將在設置Bean屬性之前調用
postProcessBeforeInitialization()
方法。 - 如果Bean類實現了
InitializingBean
接口,則在設置了配置文件中定義的所有Bean屬性后,將調用afterPropertiesSet()
方法。 - 如果配置文件中的Bean定義包含
init-method
屬性,則該屬性的值將解析為Bean類中的方法名稱,并將調用該方法。 - 如果為Bean Factory對象附加了任何Bean 后置處理器,則將調用
postProcessAfterInitialization()
方法。 - 如果Bean類實現
DisposableBean
接口,則當Application不再需要Bean引用時,將調用destroy()
方法。 - 如果配置文件中的Bean定義包含
destroy-method
屬性,那么將調用Bean類中的相應方法定義。
實例演示
接下來,我們用一個簡單的DEMO來演示一下,整個生命周期的流轉過程,加深你的印象。
- 定義一個
Person
類,實現了DisposableBean, InitializingBean, BeanFactoryAware, BeanNameAware
這4個接口,同時還有自定義的init-method
和destroy-method
。這里,如果不了解這幾個接口的讀者,可以先去看看這幾個接口的定義。
public class Person implements DisposableBean, InitializingBean, BeanFactoryAware, BeanNameAware {
private String name;
Person() {
System.out.println("Constructor of person bean is invoked!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("setBeanFactory method of person is invoked");
}
@Override
public void setBeanName(String name) {
System.out.println("setBeanName method of person is invoked");
}
public void init() {
System.out.println("custom init method of person bean is invoked!");
}
//Bean initialization code equals to
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet method of person bean is invoked!");
}
//Bean destruction code
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean Destroy method of person bean is invoked!");
}
public void destroyMethod() {
System.out.println("custom Destroy method of person bean is invoked!");
}
}
- 定義一個
MyBeanPostProcessor
實現BeanPostProcessor
接口。
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("post Process Before Initialization is invoked");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("post Process after Initialization is invoked");
return bean;
}
}
- 配置文件,指定
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 name="myBeanPostProcessor" class="ric.study.demo.ioc.life_cycle_demo_set.MyBeanPostProcessor" />
<bean name="personBean" class="ric.study.demo.ioc.life_cycle_demo_set.Person"
init-method="init" destroy-method="destroyMethod">
<property name="name" value="Richard Yi" />
</bean>
</beans>
- 啟動容器、銷毀容器
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config-1.xml");
((ClassPathXmlApplicationContext) context).destroy();
}
}
- 輸出
Constructor of person bean is invoked!
setBeanName method of person is invoked
setBeanFactory method of person is invoked
post Process Before Initialization is invoked
afterPropertiesSet method of person bean is invoked!
custom init method of person bean is invoked!
post Process after Initialization is invoked
DisposableBean Destroy method of person bean is invoked!
custom Destroy method of person bean is invoked!
可以看到這個結果和我們上面描述的一樣。
源碼解析
下面我們從源碼角度來看看,上述描述的調用是如何實現的。
實際上如果你看過我之前的文章 Spring IoC 依賴注入 源碼解析的話,應該知道上述調用的具體實現。
這里相當于把相關部分再拎出來講一遍。
容器初始化
Spring IoC 依賴注入的階段,創建Bean有三個關鍵步驟
- createBeanInstance() 實例化
- populateBean(); 屬性裝配
- initializeBean() 處理Bean初始化之后的各種回調事件
其中,initializeBean()
負責處理Bean初始化后的各種回調事件。
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
// 涉及到的回調接口點進去一目了然,代碼都是自解釋的
// BeanNameAware、BeanClassLoaderAware或BeanFactoryAware
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// BeanPostProcessor 的 postProcessBeforeInitialization 回調
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// init-methods
// 或者是實現了InitializingBean接口,會調用afterPropertiesSet() 方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// BeanPostProcessor 的 postProcessAfterInitialization 回調
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
其中invokeAwareMethods
會先調用一系列的***Aware
接口實現
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) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
然后再執行 BeanPostProcessor
的 postProcessBeforeInitialization
回調
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
然后再調用 初始化方法,其中包括 InitializingBean
的afterPropertiesSet
方法和指定的init-method
方法,
protected void invokeInitMethods(String beanName, final Object bean, 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(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
((InitializingBean) bean).afterPropertiesSet();
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null) {
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
最后再執行 BeanPostProcessor
的 postProcessAfterInitialization
回調
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
好的,到這里我們介紹了Spring 容器初始化過程Bean加載過程當中的各種回調實現,下面介紹Spring 容器銷毀階段。
容器關閉
與Bean初始化類似,當容器關閉時,可以看到對Bean銷毀方法的調用。銷毀過程是這樣的。順著close()-> doClose() -> destroyBeans() -> destroySingletons() -> destroySingleton() -> destroyBean() -> bean.destroy()
,會看到最終調用Bean的銷毀方法。
protected void destroyBean(String beanName, DisposableBean bean) {
// 忽略
// Actually destroy the bean now...
if (bean != null) {
try {
bean.destroy();
}
catch (Throwable ex) {
logger.error("Destroy method on bean with name '" + beanName + "' threw an exception", ex);
}
}
// 忽略
}
這里注意哦,這個Bean的類型實際上是DisposableBeanAdapter
,DisposableBeanAdapter
是管理Spring Bean的銷毀的,實際上這里運用了適配器模式。再來看看destroy()
的具體方法。
@Override
public void destroy() {
if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
processor.postProcessBeforeDestruction(this.bean, this.beanName);
}
}
if (this.invokeDisposableBean) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'");
}
try {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
((DisposableBean) bean).destroy();
return null;
}
}, acc);
}
else {
// 調用 DisposableBean 的 destroy()方法
((DisposableBean) bean).destroy();
}
}
catch (Throwable ex) {
String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {
logger.warn(msg, ex);
}
else {
logger.warn(msg + ": " + ex);
}
}
}
if (this.destroyMethod != null) {
// 調用 設置的destroyMethod
invokeCustomDestroyMethod(this.destroyMethod);
}
else if (this.destroyMethodName != null) {
Method methodToCall = determineDestroyMethod();
if (methodToCall != null) {
invokeCustomDestroyMethod(methodToCall);
}
}
}
BeanPostProcessor 是什么時候注冊到容器的?
前面只介紹了BeanPostProcessor類在 Spring Bean 生命周期中的回調實現,卻沒有說明 BeanPostProcessor 是什么時候注冊到容器的。下面我們來介紹下。
在Spring IoC 容器初始化的時候,容器會做一些初始化操作,其中就包括了BeanPostProcessor的register過程。詳細的過程可以看我這篇IoC 容器初始化。
這里直接放源碼吧。
源碼位置AbstractApplicationContext#refresh()
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 在這里
registerBeanPostProcessors(beanFactory);
// ....忽略
}
}
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
源碼位置PostProcessorRegistrationDelegate#registerBeanPostProcessors()
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// step1
// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// step2
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
List<String> orderedPostProcessorNames = new ArrayList<String>();
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// step3
// First, register the BeanPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implement Ordered.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// Finally, re-register all internal BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
上述過程可以分成四步:
- 通過
beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
方法獲取beanFactory里繼承了BeanPostProcessor接口的name的集合; - 把后置器beans分為
PriorityOrdered、Ordered、nonOrdered
三大類,前兩類是增加了排序條件的后置器;(Spring可以通過PriorityOrdered
和Ordered
接口控制處理器的優先級),這里實際上還有一類是MergedBeanDefinitionPostProcessor
,不是核心點,不展開講。 - 第三步可以分為以下小步
-
priorityOrderedPostProcessors
,先排序后注冊 -
orderedPostProcessors
,先排序后注冊 - 注冊
nonOrderedPostProcessors
,就是一般的處理器 -
internalPostProcessors
,先排序后注冊 - 注冊一個
ApplicationListenerDetector
的 processor
-
DisposableBeanAdapter 什么時候注冊到容器的?
DisposableBeanAdapter
和上文的BeanPostProcessor
的抽象層級不同,這個是和Bean綁定的,所以它的注冊時機是在Spring Bean的依賴注入階段,詳細源碼可以看我的這篇文章Spring IoC 依賴注入 源碼解析。
源碼位置:AbstractAutowireCapableBeanFactory#doCreateBean()
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// 省略前面的超多步驟,想了解的可以去看源碼或者我的那篇文章
// Register bean as disposable.
// 這里就是DisposableBeanAdapter的注冊步驟了
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
源碼位置:AbstractBeanFactory#registerDisposableBeanIfNecessary()
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
// 注冊一個DisposableBean實現,該實現將執行給定bean的所有銷毀工作。
// 包括:DestructionAwareBeanPostProcessors,DisposableBean接口,自定義destroy方法。
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else {
// A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}
結語
至此,Spring Bean的整個生命周期算是講解完了,從容器初始化到容器銷毀,以及回調事件的注冊時機等方面都說明了一下,希望能對你有所幫助。
本文由博客一文多發平臺 OpenWrite 發布!