Bean 生命周期
- 0. 聲明
- 1. 引言
- 2. 生命周期的概要流程
- 3. 擴充點的作用
-
- 3.1 Aware 接口
- 3.2 BeanPostProcessor
- 3.3 InitializingBean 和 init-method
- 4. 總結
0. 聲明
Bean
生命周期可謂是面試的重點,恰好看到這篇生命周期講解極為清楚的一篇文章,故轉載。如何記憶 Spring Bean 的生命周期
1. 引言
“請你描述下
Spring Bean
的生命周期?”,這是面試官考察
Spring
的常用問題,可見是
Spring
中很重要的知識點。
我之前在準備面試時,去網上搜過答案,大多以下圖給出的流程作為答案。
但是當我第一次看到該圖時,就産生了很多困擾,“
Aware
,
BeanPostProcessor
…這些都是什麼啊!而且這麼多步驟,太多了,該怎麼記啊!”。
其實要記憶該過程,還是需要我們先去了解,本文将從以下兩方面去幫助了解 Bean 的生命周期:
- 生命周期的概要流程:對
的生命周期進行概括,并且結合代碼來了解;Bean
- 擴充點的作用:詳細介紹
生命周期中所涉及到的擴充點的作用。Bean
2. 生命周期的概要流程
Bean
的生命周期概括起來就是
4
個階段:
- 執行個體化(
);Instantiation
- 屬性指派(
);Populate
- 初始化(
);Initialization
- 銷毀(
)。Destruction
- 執行個體化:第
步,執行個體化一個1
對象;bean
- 屬性指派:第
步,為2
設定相關屬性和依賴;bean
- 初始化:第
步,步驟較多,其中第3~7
步為初始化操作,第5、6
步為在初始化前執行,第3、4
步在初始化後執行,該階段結束,才能被使用者使用;7
- 銷毀:第
步,第8~10
步不是真正意義上的銷毀(還沒使用呢),而是先在使用前注冊了銷毀的相關調用接口,為了後面第8
步真正銷毀9、10
時再執行相應的方法。bean
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 1. 執行個體化
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object exposedObject = bean;
try {
// 2. 屬性指派
populateBean(beanName, mbd, instanceWrapper);
// 3. 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// 4. 銷毀-注冊回調接口
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
return exposedObject;
}
由于初始化包含了第
3~7
步,較複雜,是以我們進到
initializeBean()
方法裡具體看下其過程(注釋的序号對應圖中序号):
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 3. 檢查 Aware 相關接口并設定相關依賴
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
// 4. BeanPostProcessor 前置處理
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// 5. 若實作 InitializingBean 接口,調用 afterPropertiesSet() 方法
// 6. 若配置自定義的 init-method方法,則執行
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
// 7. BeanPostProceesor 後置處理
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
在
invokInitMethods()
方法中會檢查
InitializingBean
接口和
init-method
方法,銷毀的過程也與其類似:
// DisposableBeanAdapter.java
public void destroy() {
// 9. 若實作 DisposableBean 接口,則執行 destory()方法
if (this.invokeDisposableBean) {
try {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((DisposableBean) this.bean).destroy();
return null;
}, this.acc);
}
else {
((DisposableBean) this.bean).destroy();
}
}
}
// 10. 若配置自定義的 detory-method 方法,則執行
if (this.destroyMethod != null) {
invokeCustomDestroyMethod(this.destroyMethod);
}
else if (this.destroyMethodName != null) {
Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
if (methodToInvoke != null) {
invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
}
}
}
從
Spring
的源碼我們可以直覺的看到其執行過程,而我們記憶其過程便可以從這
4
個階段出發,執行個體化、屬性指派、初始化、銷毀。其中細節較多的便是初始化,涉及了
Aware
、
BeanPostProcessor
、
InitializingBean
、
init-method
的概念。這些都是
Spring
提供的擴充點,其具體作用将在下一節講述。
3. 擴充點的作用
3.1 Aware 接口
若
Spring
檢測到
bean
實作了
Aware
接口,則會為其注入相應的依賴。是以通過讓
bean
實作
Aware
接口,則能在
bean
中獲得相應的
Spring
容器資源。
Spring
中提供的
Aware
接口有:
-
:注入目前BeanNameAware
對應bean
;beanName
-
:注入加載目前BeanClassLoaderAware
的bean
;ClassLoader
-
:注入 目前BeanFactoryAware
容器 的引用。BeanFactory
其代碼實作如下:
// AbstractAutowireCapableBeanFactory.java
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(bcl);
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
以上是針對
BeanFactory
類型的容器,而對于
ApplicationContext
類型的容器,也提供了
Aware
接口,隻不過這些
Aware
接口的注入實作,是通過
BeanPostProcessor
的方式注入的,但其作用仍是注入依賴。
-
:注入EnvironmentAware
,一般用于擷取配置屬性;Enviroment
-
:注入EmbeddedValueResolverAware
(EmbeddedValueResolver
解析器),一般用于參數解析;Spring EL
-
(ApplicationContextAware
、ResourceLoader
、ApplicationEventPublisherAware
):注入MessageSourceAware
容器本身。ApplicationContext
其代碼實作如下:
// ApplicationContextAwareProcessor.java
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware)bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
}
}
3.2 BeanPostProcessor
BeanPostProcessor
是
Spring
為修改
bean
提供的強大擴充點,其可作用于容器中所有
bean
,其定義如下:
public interface BeanPostProcessor {
// 初始化前置處理
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
// 初始化後置處理
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
常用場景有:
- 對于标記接口的實作類,進行自定義處理。例如
節中所說的3.1
,為其注入相應依賴;再舉個例子,自定義對實作解密接口的類,将對其屬性進行解密處理;ApplicationContextAwareProcessor
- 為目前對象提供代理實作。例如
功能,生成對象的代理類,然後傳回。Spring AOP
// AbstractAutoProxyCreator.java
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
// 傳回代理類
return proxy;
}
return null;
}
3.3 InitializingBean 和 init-method
InitializingBean
和
init-method
是
Spring
為
bean
初始化提供的擴充點。
InitializingBean
接口的定義如下:
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
在
afterPropertiesSet()
方法寫初始化邏輯。
指定
init-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 id="demo" class="com.chaycao.Demo" init-method="init()"/>
</beans>
DisposableBean
和
destory-method
與上述類似,就不描述了。
4. 總結
最後總結下如何記憶
Spring Bean
的生命周期:
- 首先是執行個體化、屬性指派、初始化、銷毀這 4 個大階段;
- 再是初始化的具體操作,有
接口的依賴注入、Aware
在初始化前後的處理以及BeanPostProcessor
和InitializingBean
的初始化操作;init-method
- 銷毀的具體操作,有注冊相關銷毀回調接口,最後通過
和DisposableBean
進行銷毀。destory-method