Spring——AOP原理及源碼四【系列完】


前情回顧:

  上文我們一路分析了從容器創建開始直到我們的AOP注解導入的核心組件AnnotationAwareAspectJAutoProxyCreator執行postProcessBeforeInstantiation()方法的整個過程

  分析得到:在所有bean創建之前,都會調用resolveBeforeInstantiation方法來試圖返回一個代理對象


 

本篇預告

下圖可以看到resolveBeforeInstantiation方法包含了

applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);

applyBeanPostProcessorsAfterInitialization(bean, beanName);

兩個方法

 

在本篇我們將完整走完 resolveBeforeInstantiation 全過程,並一直到返回代理對象為止


 

 

1、調試的起點

  開始調試,還是一路跳到下一斷點,直到AbstractAutoProxyCreator.postProcessBeforeInstantiation()(從resolveBeforeInstantiation方法進入到這里的過程上一篇已經分析了)

 

可以看到當前的bean為org.springframework.context.event.internalEventListenerProcessor,和我們要測試的AOP無關。

因為當前方法打上了斷點,所以我們調到下一個斷點直到來到class aop.MathCalculator

 1 @Override
 2     public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
 3         Object cacheKey = getCacheKey(beanClass, beanName);
 4 
 5         if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
 6             if (this.advisedBeans.containsKey(cacheKey)) {
 7                 return null;
 8             }
 9             if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
10                 this.advisedBeans.put(cacheKey, Boolean.FALSE);
11                 return null;
12             }
13         }
14 
15         // Create proxy here if we have a custom TargetSource.
16         // Suppresses unnecessary default instantiation of the target bean:
17         // The TargetSource will handle target instances in a custom fashion.
18         if (beanName != null) {
19             TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
20             if (targetSource != null) {
21                 this.targetSourcedBeans.add(beanName);
22                 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
23                 Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
24                 this.proxyTypes.put(cacheKey, proxy.getClass());
25                 return proxy;
26             }
27         }
28 
29         return null;
30     }
postProcessBeforeInstantiation

 

從上往下一步步step voer,下面是對應行的講解

3、獲取bean在容器中的緩存

5、判斷目標源Bean中是否存在有當前bean的緩存信息。

(可以在21行看到添加目標源bean的操作,在23行就創建了代理對象。所以這步也是相當於判斷當前bean是否已經創建過代理對象。

  因為是第一次執行MathCalculator這個bean,這里我們是進入判斷的

  接下來 this.advisedBeans.containsKey(cacheKey) 判斷advisedBeans中是否有緩存(這里我們將advisedBeans稱為增強器)

  我們這里判斷是不滿足的,接着往下走。

9、進行 isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName) 判斷

  下面分別進入第九行的兩個方法進行查看。


 

  1、isInfrastructureClass(beanClass) 是否是基礎類型

    進入后我們會發現有如下兩個方法

    super.isInfrastructureClass(beanClass) || this.aspectJAdvisorFactory.isAspect(beanClass)

  

 

  先進入父類的 isInfrastructureClass 方法,經過一系列判斷,最后返回false,表明當前bean不是基礎類型。

 

   

   

  接着來到 isAspect(beanClass) ,通過類上是否有@Aspect注解來判斷這個類是否是切面(這里 MathCalculator顯然不是一個切面

  

 

   返回出來可以看到 isInfrastructureClass(beanClass) 的判斷為false

  

  

  2、shouldSkip 判斷是否要跳過

  

 

  在方法中遍歷所有的增強器,紅框中表面獲取的增強器便是日志方法。  

  並判斷增強器是否是AspectJPointcutAdvisor類型,我們這里判斷不滿足

  末尾來到父類的  shouldSkip 方法,進入可以看到直接返回了 false

  

 

   

最終我們來到外層的判斷,可以看到返回了false


 

2、退出 applyBeanPostProcessorsBeforeInstantiation 方法

接着來到下面這塊代碼,看注釋表明如果存在自定義目標Source,我們將在此創建代理對象

step voer,在259行判斷targetSource為null,所以這里是沒有自定義目標Source的

我們一直往下走,走完 applyBeanPostProcessorsBeforeInstantiation 方法,直到回到 resolveBeforeInstantiation 方法,返回的bean為null

所以接下來也不會進入 applyBeanPostProcessorsAfterInitialization 方法

 

到此為止,我們的 resolveBeforeInstantiation 方法執行完了,從以上可以得知,方法沒有給我們返回代理對象

如下圖所示,我們將接着執行 createBean 流程,接下來將調用 doCreateBean 


 

3、postProcessAfterInitialization方法探究

我們執行 doCreateBean 方法,來到了配置類的bean方法

 

接着跳到下一個斷點直到 postProcessAfterInitialization 方法,下面的方法棧我們是熟悉的

從finishBeanFactoryInitialization一路到initializeBean

 

不過我們現在進入的是postProcessAfterInitialization 

從下圖的 initializeBean 方法的流程也可以看明白

前面執行完了 applyBeanPostProcessorsBeforeInitialization 和 invokeInitMethods 兩個方法

 

下面進入 postProcessAfterInitialization 方法:

  如果先前的代理參考中不存在當前bean對象,就調用 wrapIfNecessary(bean, beanName, cacheKey) 並返回其結果

  

 

   進入wrapIfNecessary(進行包裝如果需要的話):

 1 /**
 2      * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
 3      * @param bean the raw bean instance
 4      * @param beanName the name of the bean
 5      * @param cacheKey the cache key for metadata access
 6      * @return a proxy wrapping the bean, or the raw bean instance as-is
 7      */
 8     protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
 9         if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
10             return bean;
11         }
12         if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
13             return bean;
14         }
15         if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
16             this.advisedBeans.put(cacheKey, Boolean.FALSE);
17             return bean;
18         }
19 
20         // Create proxy if we have advice.
21         Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
22         if (specificInterceptors != DO_NOT_PROXY) {
23             this.advisedBeans.put(cacheKey, Boolean.TRUE);
24             Object proxy = createProxy(
25                     bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
26             this.proxyTypes.put(cacheKey, proxy.getClass());
27             return proxy;
28         }
29 
30         this.advisedBeans.put(cacheKey, Boolean.FALSE);
31         return bean;
32     }
wrapIfNecessary

 

9~18行:還是先進行判斷,是否是基礎類型等,在這里我們判斷都不是

21:拿到增強器放入 Object[] specificInterceptors 中

24~25:傳入拿到的增強器等信息,創建代理對象

下面我們着重來看 getAdvicesAndAdvisorsForBean 拿增強器的過程:

  一進來先調用findEligibleAdvisors,找到合格的增強器(日志方法)

  

 

   進入findEligibleAdvisors,方法先調用findCandidateAdvisors,獲取所有候選增強器

  然后又調用findAdvisoersThatCanApply從候選增強器中選出可以用於當前bean的

  接着判斷選出的增強器隊列不為空,就給其排序,最后返回選出的增強器隊列

   

   

   findCandidateAdvisors 我們就不說了

  重點看看 findAdvisoersThatCanApply

  如下圖,可以發現它是利用AopUtils,也就是AOP工具類進行篩選

   

 

   進入工具類方法,看到方法又進行了一層判斷,將最終符合條件的增強器(日志方法)放入選擇隊列中

   

 

   獲取完后我們一路返回,又回到了 findEligibleAdvisors

  如下圖可以看到,最終排序完后將返回有五個增強器的增強器隊列

 


 

 

4、創建代理對象

最終我們獲取到了需要的增強器(日志方法)放入一個叫特殊攔截器的數組(這里暫且稱為攔截器數組)

判斷不為空后,將當前bean的緩存放入adviseBeans 中

接着調用createProxy來創建代理對象

 

 

 

 1 /**
 2      * Create an AOP proxy for the given bean.
 3      * @param beanClass the class of the bean
 4      * @param beanName the name of the bean
 5      * @param specificInterceptors the set of interceptors that is
 6      * specific to this bean (may be empty, but not null)
 7      * @param targetSource the TargetSource for the proxy,
 8      * already pre-configured to access the bean
 9      * @return the AOP proxy for the bean
10      * @see #buildAdvisors
11      */
12     protected Object createProxy(
13             Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
14 
15         if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
16             AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
17         }
18 
19         ProxyFactory proxyFactory = new ProxyFactory();
20         proxyFactory.copyFrom(this);
21 
22         if (!proxyFactory.isProxyTargetClass()) {
23             if (shouldProxyTargetClass(beanClass, beanName)) {
24                 proxyFactory.setProxyTargetClass(true);
25             }
26             else {
27                 evaluateProxyInterfaces(beanClass, proxyFactory);
28             }
29         }
30 
31         Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
32         proxyFactory.addAdvisors(advisors);
33         proxyFactory.setTargetSource(targetSource);
34         customizeProxyFactory(proxyFactory);
35 
36         proxyFactory.setFrozen(this.freezeProxy);
37         if (advisorsPreFiltered()) {
38             proxyFactory.setPreFiltered(true);
39         }
40 
41         return proxyFactory.getProxy(getProxyClassLoader());
42     }
createProxy

從上往下看

19行創建代理對象對象工廠proxyFactory ,31~34在代理對象工廠中加入增強器、目標Source等屬性
41行調用proxyFactory.getProxy(getProxyClassLoader()) 獲取當前bean的代理對象

 

 

先創建Aop代理對象

 

可以看到結果一系列調用后來到下圖,有3種動態代理對象可能返回,我們這里返回的是Cglib動態代理對象

 

一步步將代理對象返回,執行完當前bean的 applyBeanPostProcessorsAfterInitialization方法,返回其代理對象

 

 

 

代理類的結構

 

 

 

上圖中targetSource即為目標代理類,advisors為增強器鏈

即代理類對目標類和切面類進行了兩次包裝

(1、先將目標類和切面類裝入AdvisedSupport 2、將AdvisedSupport作為自身的屬性)

 

 

可以得知:返回的代理對象將代替bean對象存入容器中

到此為止,我們的代理對象創建步驟就完成了。


 

總結:

  initializeBean方法在初始化bean時,將通過 applyBeanPostProcessorsAfterInitialization 創建並返回目標bean的代理對象,並存入容器中。

  目前為止的過程,都是在初始化bean前完成的

  下面兩張圖中的代碼流程是關鍵

  

 1、initializeBean流程

  initializeBean重要流程

  

 2、refresh流程(AOP中我們需要了解的)

  1. postProcessBeanFactory(beanFactory);
  2. invokeBeanFactoryPostProcessors(beanFactory);
  3. finishBeanFactoryInitialization(beanFactory);

refresh完整流程參考如下:

 1 @Override
 2     public void refresh() throws BeansException, IllegalStateException {
 3         synchronized (this.startupShutdownMonitor) {
 4             // Prepare this context for refreshing.
 5             prepareRefresh();
 6 
 7             // Tell the subclass to refresh the internal bean factory.
 8             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 9 
10             // Prepare the bean factory for use in this context.
11             prepareBeanFactory(beanFactory);
12 
13             try {
14                 // Allows post-processing of the bean factory in context subclasses.
15                 postProcessBeanFactory(beanFactory);
16 
17                 // Invoke factory processors registered as beans in the context.
18                 invokeBeanFactoryPostProcessors(beanFactory);
19 
20                 // Register bean processors that intercept bean creation.
21                 registerBeanPostProcessors(beanFactory);
22 
23                 // Initialize message source for this context.
24                 initMessageSource();
25 
26                 // Initialize event multicaster for this context.
27                 initApplicationEventMulticaster();
28 
29                 // Initialize other special beans in specific context subclasses.
30                 onRefresh();
31 
32                 // Check for listener beans and register them.
33                 registerListeners();
34 
35                 // Instantiate all remaining (non-lazy-init) singletons.
36                 finishBeanFactoryInitialization(beanFactory);
37 
38                 // Last step: publish corresponding event.
39                 finishRefresh();
40             }
41 
42             catch (BeansException ex) {
43                 if (logger.isWarnEnabled()) {
44                     logger.warn("Exception encountered during context initialization - " +
45                             "cancelling refresh attempt: " + ex);
46                 }
47 
48                 // Destroy already created singletons to avoid dangling resources.
49                 destroyBeans();
50 
51                 // Reset 'active' flag.
52                 cancelRefresh(ex);
53 
54                 // Propagate exception to caller.
55                 throw ex;
56             }
57 
58             finally {
59                 // Reset common introspection caches in Spring's core, since we
60                 // might not ever need metadata for singleton beans anymore...
61                 resetCommonCaches();
62             }
63         }
64     }
refresh

 

  在下一篇中,也是本系列的最后一篇,我們將探究增強器(日志方法)是如何通過代理對象,在代理對象方法執行的時候發揮作用的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM