您好,登錄后才能下訂單哦!
本篇內容介紹了“Spring的Aware注入源碼分析”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
Aware注入
在使用Spring的時候我們將自己的Bean實現BeanNameAware接口、BeanFactoryAware接口等,依賴容器幫我們注入當前Bean的名稱或者Bean工廠,其代碼實現的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行的實現:
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接口的實現類會調用setBeanName方法、如果bean是BeanClassLoaderAware接口的實現類會調用setBeanClassLoader方法、如果是BeanFactoryAware接口的實現類會調用setBeanFactory方法,注入對應的屬性值。
調用BeanPostProcessor的postProcessBeforeInitialization方法
上面initializeBean方法再看16行其實現:
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接口實現,調用postProcessBeforeInitialization方法,這個接口的調用時機之后會總結,這里就代碼先簡單提一下。
調用初始化方法
initializeBean方法的20行,調用Bean的初始化方法,看一下實現:
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的實現類,是的話,將Bean強轉為InitializingBean,直接調用afterPropertiesSet()方法
2、嘗試去拿init-method,假如有的話,通過反射,調用initMethod
因此,兩種方法各有優劣:使用實現InitializingBean接口的方式效率更高一點,因為init-method方法是通過反射進行調用的;從另外一個角度講,使用init-method方法之后和Spring的耦合度會更低一點。具體使用哪種方式調用初始化方法,看個人喜好。
調用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,調用postProcessAfterInitialization方法。因此對于BeanPostProcessor方法總結一下:
1、在初始化每一個Bean的時候都會調用每一個配置的BeanPostProcessor的方法
2、在Bean屬性設置、Aware設置后調用postProcessBeforeInitialization方法
3、在初始化方法調用后調用postProcessAfterInitialization方法
注冊需要執行銷毀方法的Bean
接下來看一下最上面doCreateBean方法的第83行registerDisposableBeanIfNecessary(beanName, bean, mbd)這一句,完成了創建Bean的最后一件事情:注冊需要執行銷毀方法的Bean。
看一下方法的實現:
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方法的實現為:
protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
return (bean != null &&
(bean instanceof DisposableBean || mbd.getDestroyMethodName() != null ||
hasDestructionAwareBeanPostProcessors()));
}
要注冊銷毀方法,Bean需要至少滿足以下三個條件之一:
(1)Bean是DisposableBean的實現類,此時執行DisposableBean的接口方法destroy()
(2)Bean標簽中有配置destroy-method屬性,此時執行destroy-method配置指定的方法
(3)當前Bean對應的BeanFactory中持有DestructionAwareBeanPostProcessor接口的實現類,此時執行DestructionAwareBeanPostProcessor的接口方法postProcessBeforeDestruction
在滿足上面三個條件之一的情況下,容器便會注冊銷毀該Bean,注冊Bean的方法很簡單,見registerDisposableBean方法實現:
public void registerDisposableBean(String beanName, DisposableBean bean) {
synchronized (this.disposableBeans) {
this.disposableBeans.put(beanName, bean);
}
}
容器銷毀的時候,會遍歷disposableBeans,逐一執行銷毀方法。
“Spring的Aware注入源碼分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。