前文BeanPostProcessor解析、FactoryBean的使用和bean循環依賴是對這節內容的細化,這節相當于對bean做個總結。
InstantiationAwareBeanPostProcessor前置處理
在目標對象實例化之前調用,該方法的返回值類型是Object,我們可以返回任何類型的值。由于這個時候目標對象還未實例化,所以這個返回值可以用來代替原本該生成的目標對象的實例(比如代理對象)。如果該方法的返回值代替原本該生成的目標對象,后續只有postProcessAfterInitialization方法會調用,其它方法不再調用;否則按照正常的流程走
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
實例化bean
實例化bean有三種方式:
- 無參構造,這種是最簡單的,獲得beanClass,然后反射創建。
- 有參構造,比較麻煩,需要匹配參數,調用合適的構造方法。
- 工廠方法調用,直接調用方法創建bean,比如@bean聲明的方法。
實例化對象被包裝在BeanWrapper對象中,BeanWrapper提供了設置對象屬性的接口,從而避免了使用反射機制設置屬性。
具體代碼實現在AbstractAutowireCapableBeanFactory#createBeanInstance
屬性填充
具體實現代碼在AbstractAutowireCapableBeanFactory#populateBean中。
populateBean函數處理的流程如下:
- InstantiationAwareBeanPostProcessor處理器的postProcessAfterInstantiation函數的應用,此函數可以控制程序是否繼續進行屬性填充。
- 根據注入類型(byName/byType),提取依賴的bean,并統一存入PropertyValues。
- 應用InstantiationAwareBeanPostProcessor處理器的postProcessPropertyValues,對屬性獲取完畢填充前對屬性的再次處理。
- 將所有的PropertyValues中的屬性填充至BeanWrapper中。
注入Aware接口
Spring會檢測該對象是否實現了xxxAware接口,并將相關的xxxAware實例注入給bean。
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);
}
}
}
BeanPostProcessorc處理
這步可以對bean進行處理改造,詳情可以參考BeanPostProcessor解析
InitializingBean與init-method
檢查bean是否實現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);
}
}
}
注冊DisposableBean
Spring中不但提供了對于初始化方法的擴展入口,同樣也提供了銷毀方法的擴展入口,對于銷毀方法的擴展,除了我們熟知的配置屬性destory-method方法外,用戶還可以注冊后處理器DestructionAwareBeanPostProcessor來統一處理bean的銷毀方法。
檢查FactoryBean接口
參考文章
- https://www.zhihu.com/question/38597960
- 《Spring源碼深度解析》