前言
本系列全部基於 Spring 5.2.2.BUILD-SNAPSHOT
版本。因為 Spring 整個體系太過於龐大,所以只會進行關鍵部分的原始碼解析。
本篇文章主要介紹 Spring IoC 容器中 bean
的初始化階段。
正文
我們在Spring IoC bean 的建立一文中分析建立 bean
例項的主要流程,此時建立出來的 bean
還是個屬性未賦值的例項,在建立完之後會進入 populateBean()
方法,即進入屬性賦值階段。我們簡單回顧一下,上次分析過的 doCreateBean()
方法:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
// 例項化 bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 如果bean的作用域是singleton,則需要移除未完成的FactoryBean例項的快取
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 通過建構函式反射建立bean的例項,但是屬性並未賦值,見下文詳解
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 獲取bean的例項
final Object bean = instanceWrapper.getWrappedInstance();
// 獲取bean的型別
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// BeanDefinition 合併後的回撥,見下文詳解
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
// 省略異常處理...
mbd.postProcessed = true;
}
}
// bean的作用域是單例 && 允許迴圈引用 && 當前bean正在建立中
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
// 如果允許bean提前曝光
if (earlySingletonExposure) {
// 將beanName和ObjectFactory形成的key-value對放入singletonFactories快取中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 給 bean 的屬性賦值
populateBean(beanName, mbd, instanceWrapper);
// 初始化 bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// 省略部分程式碼
}
上篇文章分析了 populateBean()
方法,這次我們總店分析 initializeBean()
方法。
bean 的初始化
AbstractAutoCapableBeanFactory#initializeBean
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// BeanAware的介面回撥,見下文詳解
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// BeanPostProcessor的postProcessBeforeInitialization()回撥,也就是bean初始化前的回撥
// 在 ApplicationContextAwareProcessor實現的postProcessBeforeInitialization方法中會執行
// ApplicationContext Aware的介面回撥。
// InitDestoryAnnotationBeanPostProcessor的postProcessBeforeInitialization()中會執行
// 標註了@PostConstruct註解的方法。
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 呼叫bean的自定義初始化方法,如afterPropertiesSet,XML中的init屬性指定的方法等
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()回撥,也就是bean初始化後的回撥
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
Aware 介面回撥
AbstractAutowireCapableBeanFactory#invokeAwareMethods
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
// BeanNameAware介面方法回撥
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
// BeanClassLoaderAware介面方法回撥
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
// BeanFactoryAware介面方法回撥
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware)bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
通過實現這些 Aware
介面的 bean
的被初始化之前,可以取得一些相對應的資源,比如 beanName
、beanFactory
等。
bean 的初始化前回撥
AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
Object result = existingBean;
// 遍歷所有註冊的BeanPostProcessor實現類,呼叫postProcessBeforeInitialization方法
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 在bean初始化方法執行前,呼叫postProcessBeforeInitialization方法
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
上面方法主要是呼叫了 BeanPostProcessor
的 postProcessBeforeInitialization()
方法,下面我們看一下 BeanPostProcessor
介面的定義:
public interface BeanPostProcessor {
/**
* bean初始化前呼叫,此時bean已經例項化並且屬性已經賦值,Aware介面已經回撥;返回非 {@code null} 會使用返回的bean
*/
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* bean初始化後呼叫,返回非 {@code null} 會使用返回的bean
*/
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
呼叫初始化方法
AbstractAutowireCapableBeanFactory#invokeInitMethods
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
// bean是否實現InitializingBean介面
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
// 呼叫afterPropertiesSet方法
((InitializingBean) bean).afterPropertiesSet();
}
// 呼叫自定義的init方法,例如XML中init-method屬性設定的方法
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);
}
}
}
我們知道設定 bean
的初始化方法其實有三種方式 @PostConstruct
、InitializingBean
、自定義初始化方法,一個 bean
同時實現這三種方式時,呼叫順序如下:
@PostConstruct
InitializingBean#afterPropertiesSet()
- 自定義初始化方法
從上面方法可以很容易的看出 InitializingBean
介面的 afterPropertiesSet()
方法先於自定義初始化方法呼叫,那麼 @PostConstruct
註解標註的方法在何時呼叫的呢?玄機就在上面介紹的 BeanPostProcessor
介面,InitDestroyAnnotationBeanPostProcessor
實現了該介面並重寫了 postProcessBeforeInitialization()
方法呼叫了標註 @PostConstruct
註解的方法。我會在後續文章分析其實現。
bean 初始化後回撥
AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
Object result = existingBean;
// 遍歷所有註冊的BeanPostProcessor實現類,呼叫postProcessAfterInitialization方法
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 在bean初始化方法執行後,呼叫postProcessBeforeInitialization方法
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
總結
本篇文章主要分析了 Spring IoC bean
的初始化階段流程,Spring 在此階段也提供了2個擴充套件點;分別是 bean
的初始化前和初始化後,也就是 BeanPostProcessor
介面,該介面十分重要其它 processor
介面都是直接或間接在此介面上擴充套件出來的。
最後,我模仿 Spring 寫了一個精簡版,程式碼會持續更新。地址:https://github.com/leisurexi/tiny-spring。