只要不放棄,希望遲早都會到來!
1. Bean的初始化
如果把bean的生命週期看作一個嬰兒誕生過程的,那麼建立例項相當於嬰兒從母體出來,一絲不掛光禿禿;屬性賦值相當於給寶寶的頭帶帽子,上身穿衣服、下神穿褲子、還有腳丫穿襪子;而初始化相當於教寶寶一些常規的動作,比如給寶寶吸奶,打嗝拍打,哄睡覺等,本篇繼續分析初始化原始碼。
2. 初始化流程概覽
3. 原始碼分析
進入initializeBean
方法:
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// 啟用aware介面
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 初始化前處理的beanPostProcessor , 比如aware介面,InitDestroyBeanPostProcessor,
// ImportAwareBeanPostPorcessor 對ImportAware的支援
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 啟用 init-method方法
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
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
看到流程中主要分為上述流程概覽中所述的四個步驟:
step1
:啟用aware介面;
step2
:初始化前處理的beanPostProcessor;
step3
:啟用 init-method方法;
step4
:初始化後處理的beanPostProcessor.
下面逐一分析。
啟用aware介面,原始碼如下:
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
分別對BeanNameAware、BeanClassLoaderAware、BeanFactoryAwareaware介面進行處理,設定對應的屬性;接下來進入applyBeanPostProcessorsBeforeInitialization
方法:
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
該方法對初始化前的beanPostProcessor進行處理,對比如InitDestroyBeanPostProcessor,對@PostConstruct的支援, ApplicationContextAwareProcessor對某個Aware介面方法的呼叫,ImportAwareBeanPostPorcessor對ImportAware的支援等;
接下來InitializingBean介面和init-method 屬性呼叫對應方法為invokeInitMethods:
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
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>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 呼叫afterPropertiesSet方法
((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)) {
// 呼叫自定義的init方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
afterPropertiesSet 和 Init-method 和有@PostConstruct 註解的方法其實核心功能都是一樣的,只是呼叫時序不一樣而已,都是在該類例項化和 IOC 做完後呼叫的,我們可以在這些方法中做一些在 spring 或者 servlet 容器啟動的時候的初始化工作。比如快取預熱,比如快取資料載入到記憶體,比如配置解析,等等初始化工作呼叫順序為先呼叫@PostConstruct(註解使用)、然後是 afterPropertiesSet、InitMethod(xml 配置)方法。
最後一步,初始化後處理的beanPostProcessor,這裡最主要的是完成代理的生成,該內容放到後面AOP階段再深入。
4. 總結
本篇主要分析了bean的初始化相關操作,包括@PostConstruct註解的支援,Aware介面的支援,以及初始化後的afterPropertiesSet方法以及InitMethod方法的支援,最後完成BeanPostProcessor的後置處理,生成aop代理例項,後續將繼續分析FactoryBean介面例項化物件的過程。