共計 6225 個字符,預計需要花費 16 分鐘才能閱讀完成。
本篇內(nèi)容介紹了“Spring 的 Aware 注入源碼分析”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓丸趣 TV 小編帶領(lǐng)大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!
Aware 注入
在使用 Spring 的時候我們將自己的 Bean 實現(xiàn) BeanNameAware 接口、BeanFactoryAware 接口等,依賴容器幫我們注入當前 Bean 的名稱或者 Bean 工廠,其代碼實現(xiàn)的 initializeBean 方法:
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction Object () {
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
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()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
看一下上面第 5 行的實現(xiàn):
private void invokeAwareMethods(final String beanName, final Object bean) {
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);
}
}
看到這里判斷,如果 bean 是 BeanNameAware 接口的實現(xiàn)類會調(diào)用 setBeanName 方法、如果 bean 是 BeanClassLoaderAware 接口的實現(xiàn)類會調(diào)用 setBeanClassLoader 方法、如果是 BeanFactoryAware 接口的實現(xiàn)類會調(diào)用 setBeanFactory 方法,注入對應的屬性值。
調(diào)用 BeanPostProcessor 的 postProcessBeforeInitialization 方法
上面 initializeBean 方法再看 16 行其實現(xiàn):
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
遍歷每個 BeanPostProcessor 接口實現(xiàn),調(diào)用 postProcessBeforeInitialization 方法,這個接口的調(diào)用時機之后會總結(jié),這里就代碼先簡單提一下。
調(diào)用初始化方法
initializeBean 方法的 20 行,調(diào)用 Bean 的初始化方法,看一下實現(xiàn):
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 () {
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);
}
}
}
看到,代碼做了兩件事情:
1、先判斷 Bean 是否 InitializingBean 的實現(xiàn)類,是的話,將 Bean 強轉(zhuǎn)為 InitializingBean,直接調(diào)用 afterPropertiesSet() 方法
2、嘗試去拿 init-method,假如有的話,通過反射,調(diào)用 initMethod
因此,兩種方法各有優(yōu)劣:使用實現(xiàn) InitializingBean 接口的方式效率更高一點,因為 init-method 方法是通過反射進行調(diào)用的;從另外一個角度講,使用 init-method 方法之后和 Spring 的耦合度會更低一點。具體使用哪種方式調(diào)用初始化方法,看個人喜好。
調(diào)用 BeanPostProcessor 的 postProcessAfterInitialization 方法
最后一步,initializeBean 方法的 29 行:
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
同樣遍歷 BeanPostProcessor,調(diào)用 postProcessAfterInitialization 方法。因此對于 BeanPostProcessor 方法總結(jié)一下:
1、在初始化每一個 Bean 的時候都會調(diào)用每一個配置的 BeanPostProcessor 的方法
2、在 Bean 屬性設(shè)置、Aware 設(shè)置后調(diào)用 postProcessBeforeInitialization 方法
3、在初始化方法調(diào)用后調(diào)用 postProcessAfterInitialization 方法
注冊需要執(zhí)行銷毀方法的 Bean
接下來看一下最上面 doCreateBean 方法的第 83 行 registerDisposableBeanIfNecessary(beanName, bean, mbd) 這一句,完成了創(chuàng)建 Bean 的最后一件事情:注冊需要執(zhí)行銷毀方法的 Bean。
看一下方法的實現(xiàn):
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
// Register a DisposableBean implementation that performs all destruction
// work for the given bean: DestructionAwareBeanPostProcessors,
// DisposableBean interface, custom destroy method.
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else {
// A bean with a custom scope…
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException(No Scope registered for scope + mbd.getScope() +
}
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}
其中第 3 行第一個判斷為必須不是 prototype(原型)的,第二個判斷 requiresDestruction 方法的實現(xiàn)為:
protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
return (bean != null
(bean instanceof DisposableBean || mbd.getDestroyMethodName() != null ||
hasDestructionAwareBeanPostProcessors()));
}
要注冊銷毀方法,Bean 需要至少滿足以下三個條件之一:
(1)Bean 是 DisposableBean 的實現(xiàn)類,此時執(zhí)行 DisposableBean 的接口方法 destroy()
(2)Bean 標簽中有配置 destroy-method 屬性,此時執(zhí)行 destroy-method 配置指定的方法
(3)當前 Bean 對應的 BeanFactory 中持有 DestructionAwareBeanPostProcessor 接口的實現(xiàn)類,此時執(zhí)行 DestructionAwareBeanPostProcessor 的接口方法 postProcessBeforeDestruction
在滿足上面三個條件之一的情況下,容器便會注冊銷毀該 Bean,注冊 Bean 的方法很簡單,見 registerDisposableBean 方法實現(xiàn):
public void registerDisposableBean(String beanName, DisposableBean bean) {
synchronized (this.disposableBeans) {
this.disposableBeans.put(beanName, bean);
}
}
容器銷毀的時候,會遍歷 disposableBeans,逐一執(zhí)行銷毀方法。
“Spring 的 Aware 注入源碼分析”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注丸趣 TV 網(wǎng)站,丸趣 TV 小編將為大家輸出更多高質(zhì)量的實用文章!