spring——AOP原理及源碼(四)

前情回顧:

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

  分析獲得:在全部bean建立以前,都會調用resolveBeforeInstantiation方法來試圖返回一個代理對象spring


 

本篇預告

下圖能夠看到resolveBeforeInstantiation方法包含了數組

applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);緩存

applyBeanPostProcessorsAfterInitialization(bean, beanName);app

兩個方法ide

 

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


 

 

調試的起點

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

 

能夠看到當前的bean爲org.springframework.context.event.internalEventListenerProcessor,和咱們要測試的AOP無關。測試

由於當前方法打上了斷點,因此咱們調到下一個斷點直到來到class aop.MathCalculatorui

 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,下面是對應行的講解

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

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

(能夠在21行看到添加目標源bean的操做,在23行就建立了代理對象。因此這步也是至關於判斷當前bean是否已經建立過代理對象。

  由於是第一次執行MathCalculator這個bean,這裏咱們是進入判斷的

  接下來 this.advisedBeans.containsKey(cacheKey) 判斷advisedBeans中是否有緩存(這裏咱們將advisedBeans稱爲加強器)

  咱們這裏判斷是不知足的,接着往下走。

九、進行 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


 

退出 applyBeanPostProcessorsBeforeInstantiation 方法

接着來到下面這塊代碼,看註釋代表若是存在自定義目標Source,咱們將在此建立代理對象

step voer,在259行判斷targetSource爲null,因此這裏是沒有自定義目標Source的

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

因此接下來也不會進入 applyBeanPostProcessorsAfterInitialization 方法

 

到此爲止,咱們的 resolveBeforeInstantiation 方法執行完了,從以上能夠得知,方法沒有給咱們返回代理對象

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


 

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

  以下圖能夠看到,最終排序完後將返回有五個加強器的加強器隊列

 


 

 

建立代理對象

最終咱們獲取到了須要的加強器(日誌方法)放入一個叫特殊攔截器的數組(這裏暫且稱爲攔截器數組)

判斷不爲空後,將當前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方法,返回其代理對象

 

 

 

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

到此爲止,咱們的代理對象建立步驟就完成了。


 

總結:

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

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

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

  

  initializeBean流程:

  initializeBean重要流程

  

  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

 

  在下一篇中,也是本系列的最後一篇,咱們將探究加強器(日誌方法)是如何經過代理對象,在代理對象方法執行的時候發揮做用的。

相關文章
相關標籤/搜索