在上篇文章中,咱們詳細分析了
doCreateBean()
中的第5步:屬性填充,本文接着分析doCreateBean()
的第6步——初始化 bean 實例對象java
本文轉自公衆號:芋道源碼編程
首先回顧下CreateBean
的主流程:數組
createBeanInstance()
實例化 beanSpring在對Bean進行屬性填充以後,會對Bean進行初始化,代碼以下:緩存
//AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
//JDK的安全機制驗證權限
if (System.getSecurityManager() != null) {
// <1> 激活 Aware 方法,對特殊的 bean 處理:Aware、BeanClassLoaderAware、BeanFactoryAware
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// <1> 激活 Aware 方法,對特殊的 bean 處理:Aware、BeanClassLoaderAware、BeanFactoryAware
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
// <2> 後置處理器,before
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// <3> 激活用戶自定義的 init 方法
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
// <2> 後置處理器,after
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
複製代碼
初始化 bean 的方法其實就是三個步驟的處理,而這三個步驟主要仍是根據用戶設定的來進行初始化,這三個過程爲:安全
<1> 激活 Aware 方法。app
<2> 後置處理器。ide
<3> 自定義的 init 方法。post
Aware ,英文翻譯是意識到的,感知的。Spring 提供了諸多 Aware 接口,用於輔助 Spring Bean 以編程的方式調用 Spring 容器,經過實現這些接口,能夠加強 Spring Bean 的功能。學習
Spring 提供了以下系列的 Aware 接口:spa
LoadTimeWeaverAware:加載Spring Bean時織入第三方模塊,如AspectJ
BeanClassLoaderAware:加載Spring Bean的類加載器
BootstrapContextAware:資源適配器BootstrapContext,如JCA,CCI
ResourceLoaderAware:底層訪問資源的加載器
BeanFactoryAware:聲明BeanFactory
PortletConfigAware:PortletConfig
PortletContextAware:PortletContext
ServletConfigAware:ServletConfig
ServletContextAware:ServletContext
MessageSourceAware:國際化
ApplicationEventPublisherAware:應用事件
NotificationPublisherAware:JMX通知
BeanNameAware:聲明Spring Bean的名字
Aware比較複雜,後面會專門學習一下這塊內容,這裏就很少說了。
BeanPostProcessor 在前面介紹 bean 加載的過程曾屢次遇到,
它的做用是:
若是咱們想要在 Spring 容器完成 Bean 的實例化,配置和其餘的初始化後添加一些本身的邏輯處理,那麼請使用該接口,這個接口給與了用戶充足的權限去更改或者擴展 Spring,是咱們對 Spring 進行擴展和加強處理一個必不可少的接口。
applyBeanPostProcessorsBeforeInitialization()
方法,代碼以下:
// AbstractAutowireCapableBeanFactory.java
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
Object result = existingBean;
// 遍歷 BeanPostProcessor 數組
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 處理
Object current = processor.postProcessBeforeInitialization(result, beanName);
// 返回空,則返回 result
if (current == null) {
return result;
}
// 修改 result
result = current;
}
return result;
}
複製代碼
applyBeanPostProcessorsAfterInitialization()
方法,代碼以下:
// AbstractAutowireCapableBeanFactory.java
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
Object result = existingBean;
// 遍歷 BeanPostProcessor
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 處理
Object current = processor.postProcessAfterInitialization(result, beanName);
// 返回空,則返回 result
if (current == null) {
return result;
}
// 修改 result
result = current;
}
return result;
}
複製代碼
其邏輯就是經過 getBeanPostProcessors() 方法,獲取定義的 BeanPostProcessor ,而後分別調用其 postProcessBeforeInitialization() 和 postProcessAfterInitialization() 方法,進行自定義的業務處理。
在xml中有一個< bean >標籤的配置, init-method
方法,是可讓咱們在Bean初始化的時候,先執行咱們自定義的一些邏輯。
其實就是在這裏被觸發的,代碼以下:
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
// 首先會檢查是不是 InitializingBean ,若是是的話須要調用 afterPropertiesSet()
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) { // 安全模式
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
// <1> 屬性初始化的處理
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
} catch (PrivilegedActionException pae) {
throw pae.getException();
}
} else {
// <1> 屬性初始化的處理
((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)) {
// <2> 激活用戶自定義的初始化方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
複製代碼
首先,檢查是否爲 InitializingBean 。若是是的話,須要執行 afterPropertiesSet()
方法,由於咱們除了可使用 init-method 來自定初始化方法外,還能夠實現 InitializingBean 接口。接口僅有一個 afterPropertiesSet() 方法。 二者的執行前後順序是先 <1> 的 #afterPropertiesSet() 方法,後 <2> 的 init-method 對應的方法。