聊一聊Spring是怎么將AOP應用到Bean的生命周期中的?
本系列文章:
聽說你還沒學Spring就被源碼編譯勸退了?30+張圖帶你玩轉Spring編譯
談談Spring中的對象跟Bean,你知道Spring怎么創建對象的嗎?
Spring中AOP相關的API及源碼解析,原來AOP是這樣子的
推薦閱讀:
本系列文章將會帶你一行行的將Spring的源碼吃透,推薦閱讀的文章是閱讀源碼的基礎!
前言
在上篇文章中(Spring中AOP相關的API及源碼解析,原來AOP是這樣子的)我們已經分析過了AOP的實現的源碼,那么Spring是如何將AOP應用到Bean的生命周期的呢?這篇文章就帶着大家來探究下這個問題。本文我們要分析的代碼還是位於org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
這個方法中,在《我們來談一談Spring中的屬性注入 》這篇文章中,我們已經分析過了populateBean
這個方法,
所以本文我們接着來看看initializeBean
這個方法,它主要干了這么幾件事
- 執行
Aware
接口中的方法 - 執行
生命周期回調方法
- 完成
AOP
代理
對應源碼如下:
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()) {
// 調用InitDestroyAnnotationBeanPostProcessor
// 的postProcessBeforeInitialization方法
// 處理@PostContructor注解標注的方法
// 另外有一部分aware方法也是在這里調用的
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 如果實現了InitializingBean,會調用afterPropertiesSet方法
// 如果XML中配置了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()) {
// 在這里完成AOP
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
因為在Spring官網閱讀(九)Spring中Bean的生命周期(上)文章中我們已經對這個方法做過分析了,並且這個方法本身也比較簡單,所以不再對這個方法做過多贅述,我們主要關注的就是Spring是如何將AOP
應用到Bean的生命周期中的,對應的就是applyBeanPostProcessorsAfterInitialization
這個方法,其源碼如下:
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
實際上就是調用了所有后置處理器的postProcessAfterInitialization
方法,在Spring中AOP相關的API及源碼解析,原來AOP是這樣子的一文中已經提到過了,@EnableAspectJAutoProxy
注解實際上就是向容器中注冊了一個AnnotationAwareAspectJAutoProxyCreator
,這個類本身就是一個后置處理器,AOP代理
就是由它在這一步完成的。
Bean生命周期中AOP的流程
1、@EnableAspectJAutoProxy
通過@EnableAspectJAutoProxy
注解向容器中注冊一個AnnotationAwareAspectJAutoProxyCreator
的BeanDefinition
,它本身也是一個BeanPostProcessor
,這個BeanDefinition
會在org.springframework.context.support.AbstractApplicationContext#registerBeanPostProcessors
這個方法中完成創建,如下圖所示
2、postProcessBeforeInstantiation方法執行
執行AnnotationAwareAspectJAutoProxyCreator
的postProcessBeforeInstantiation
方法,實際上就是父類AbstractAutoProxyCreator
的postProcessBeforeInstantiation
被執行
對應源碼如下:
// 這個方法的主要目的就是在不考慮通知的情況下,確認哪些Bean不需要被代理
// 1.Advice,Advisor,Pointcut類型的Bean不需要被代理
// 2.不是原始Bean被包裝過的Bean不需要被代理,例如ScopedProxyFactoryBean
// 實際上並不只是這些Bean不需要被代理,如果沒有對應的通知需要被應用到這個Bean上的話
// 這個Bean也是不需要被代理的,只不過不是在這個方法中處理的。
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
// 如果beanName為空或者為這個bean提供了定制的targetSource
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// advisedBeans是一個map,其中key是BeanName,value代表了這個Bean是否需要被代理
// 如果已經包含了這個key,不需要在進行判斷了,直接返回即可
// 因為這個方法的目的就是在實例化前就確認哪些Bean是不需要進行AOP的
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 說明還沒有對這個Bean進行處理
// 在這里會對SpringAOP中的基礎設施bean,例如Advice,Pointcut,Advisor做標記
// 標志它們不需要被代理,對應的就是將其放入到advisedBeans中,value設置為false
// 其次,如果這個Bean不是最原始的Bean,那么也不進行代理,也將其value設置為false
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 是否為這個Bean提供了定制的TargetSource
// 如果提供了定制的TargetSource,那么直接在這一步創建一個代理對象並返回
// 一般不會提供
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
3、postProcessAfterInitialization方法執行
實際上也是執行父類AbstractAutoProxyCreator
中的方法,對應源碼如下:
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 什么時候這個判斷會成立呢?
// 如果不出現循環引用的話,remove方法必定返回null
// 所以這個remove(cacheKey) != bean肯定會成立
// 如果發生循環依賴的話,這個判斷就不會成立
// 這個我們在介紹循環依賴的時候再詳細分析,
// 目前你只需要知道wrapIfNecessary完成了AOP代理
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 需要代理的話,在這里完成的代理
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
4、wrapIfNecessary方法執行
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 在postProcessBeforeInstantiation方法中可能已經完成過代理了
// 如果已經完成代理了,那么直接返回這個代理的對象
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 在postProcessBeforeInstantiation方法中可能已經將其標記為不需要代理了
// 這種情況下,也直接返回這個Bean
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 跟在postProcessBeforeInstantiation方法中的邏輯一樣
// 如果不需要代理,直接返回,同時在advisedBeans中標記成false
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 獲取可以應用到這個Bean上的通知
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果存在通知的話,說明需要被代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 到這里創建代理,實際上底層就是new了一個ProxyFactory來創建代理的
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
// 如果沒有通知的話,也將這個Bean標記為不需要代理
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
關於創建代理的具體源碼分析,在Spring中AOP相關的API及源碼解析,原來AOP是這樣子的一文中已經做了詳細介紹,所以本文不再贅述,現在我們的重點將放在Spring是如何解析出來通知的,對應方法就是getAdvicesAndAdvisorsForBean
,其源碼如下:
第一步:調用org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 通過findEligibleAdvisors方法返回對應的通知
// 這個方法回返回所有能應用在指定的Bean上的通知
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
第二步:調用org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 獲取到所有的通知
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 從獲取到的通知中篩選出能應用到這個Bean上的通知
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
第三步:調用org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
獲取到所有的通知
// 這個方法的目的就是為了獲取到所有的通知
protected List<Advisor> findCandidateAdvisors() {
// 先調用父類的方法,父類會去查找容器中所有屬於Advisor類型的Bean
List<Advisor> advisors = super.findCandidateAdvisors();
// 這個類本身會通過一個aspectJAdvisorsBuilder來構建通知
// 構建的邏輯就是解析@Aspect注解所標注的類中的方法
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
// 最后返回這些通知
return advisors;
}
第四步:org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
構建通知,這個方法比較長,我們就只分析其中的關鍵代碼即可
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
// 會獲取到容器中的所有BeanName
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
// 如果對beanName配置了正則匹配的話,那么要按照正則表達式的匹配規則進行過濾
// 默認是沒有的,可以認為isEligibleBean始終返回true
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// 判斷類上是否添加了@Aspect注解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// 默認就是SINGLETON,代理切面對象是單例的
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// 最后從這個切面實例中解析出所有的通知
// 關於通知解析的具體代碼就不再分析了
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
// 省略部分代碼
return advisors;
}
第五步:org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
這個方法其實沒啥好分析的,就是根據前面找出來的Advisor
集合進行遍歷,然后根據每個Advisor
對應的切點來進行匹配,如何合適就返回,對應源碼也比較簡單,當然前提是你看過我之前那篇AOP源碼分析
的文章了.
總結
這篇文章比較短,因為沒有做很細節的源碼分析,比較詳細的源碼分析已經放到上篇文章中了。最后我這里畫個流程圖總結一下AOP是怎么被應用到Bean的生命周期中的
Spring源碼的最后一點補充
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// 1.實例化 ---> createBeanInstance
// 2.屬性注入 ---> populateBean
// 3.初始化 ---> 完成初始化及AOP
// exposedObject 就是完成初始化后的Bean
// 省略部分代碼,省略代碼的作用已經在上面標明了
// 下面的代碼實際上主要目的在於處理循環依賴
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
// 我們之前早期暴露出去的Bean跟現在最后要放到容器中的Bean不是同一個
// allowRawInjectionDespiteWrapping為false
// 並且當前Bean被當成依賴注入到了別的Bean中
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
// 獲取到當前Bean所從屬的Bean
String[] dependentBeans = getDependentBeans(beanName);
// 要得到真實的從屬的Bean
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
// 移除那些僅僅為了類型檢查而創建出來
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
// 拋出異常
// 出現了循環依賴,並且實際存在容器中的Bean跟被當作依賴注入到別的Bean中的
// 不是同一個對象,這個時候也報錯
}
}
}
}
// 注冊bean的銷毀回調
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
實際這段代碼還是跟循環依賴相關,循環依賴是Spring中一個比較重要的話題,不管是為了面試還是更好的了解清楚Spring的流程都很有必要去弄懂它
關於Spring的循環依賴,我將在下篇文章專門分析!
如果本文對你有幫助的話,記得點個贊吧!也歡迎關注我的公眾號,微信搜索:程序員DMZ,或者掃描下方二維碼,跟着我一起認認真真學Java,踏踏實實做一個coder。
我叫DMZ,一個在學習路上匍匐前行的小菜鳥!