AOP-切面是如何織入到目標對象中的


切面是如何織入到目標對象中的???這大概是每個人在學習AOP的過程中都會產生的疑問吧。

當我們在調用目標方法時候,也就是通過代理對象調用目標方法的時候,比如:JdkDynamicAopProxy會通過連接點(ReflectiveMethodInvocation)來調用攔截器鏈中的攔截器(也就是調用通知方法)。所以JdkDynamicAopProxy對象首先要獲取的攔截器鏈條,然后才將攔截器鏈條交給連接點來調用攔截器和目標方法吧。也就是在獲取攔截器鏈條的過程中有一句代碼,這行代碼再DefaultAdvisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice(..)方法中:

if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {

我只貼這一句,建議先看下源碼。這一句代碼前半部分 config.isPreFiltered() 的意思是:config(AdvisedSupport)對象中的Advisor(每個Advisor對象持有一個通知)是否已經經過篩選並與目標對象相匹配。如果已經提前過濾好了(或者說已經提前匹配好了),那就返回true.那if判斷就為 true 了。如果說config對象中的Advisor還沒有過濾(匹配)過,那么就調用上面的這行代碼的后半部分來匹配。

但是我在debug源碼的時候發現都是已經提前匹配好了的。也就是說切面在調用目標對象之前已經織入目標對象了。那它是怎么的織入的呢??它時什么時候織入的呢??文章開頭的疑問也就是在這個時候產生的。現在我來回答這個問題:切面是在目標對象被實例化的是時候織入目標對象的,更准確的說,切面是在目標對象的bean在完成初始實例化之后bean工廠調用bean的后處理器將切面織入到目標對象中的。就像是一輛汽車生產出來之后已經可以使用了,能正常行駛了。但是最后階段我還要給它裝上儀表,安全氣囊,甚至是行車記錄儀等等。

既然既然上面所說的config對象就是AdvisedSupport類的實例那就是看看config.isPreFiltered()這句源碼

debug截圖

 

看看最關鍵的代碼,在AbstractAutoProxyCreator中的createProxy(..)中也就是上圖標出的關鍵代碼。

源碼如下:

    /**
     * Create an AOP proxy for the given bean.
     * @param beanClass the class of the bean
     * @param beanName the name of the bean
     * @param specificInterceptors the set of interceptors that is
     * specific to this bean (may be empty, but not null)
     * @param targetSource the TargetSource for the proxy,
     * already pre-configured to access the bean
     * @return the AOP proxy for the bean
     * @see #buildAdvisors
     */
    protected Object createProxy(
            Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

        if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
            AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
        }
     //ProxyFactory是AdvisedSupport的一個子類。現在創建的也就是上面所說的config對象。這個config對象將會存儲與目標對象相匹配的advisor,這就是所謂的織入。
        //等到調用目標對象的時候在將advisor取出來包裝(轉換)成攔截器。最后組成攔截器鏈。
ProxyFactory proxyFactory
= new ProxyFactory(); proxyFactory.copyFrom(this); if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) {
          proxyFactory.setProxyTargetClass(
true); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } } //這里是給定的攔截器包裝成advisor。這個specificInterceptors是作為這個方法的參數傳進來的。也就是說在這之前就已經將與目標對象相匹配的攔截器構建好了。 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); for (Advisor advisor : advisors) { //這里就是織入,將與目標對象相匹配的advisor存儲到config中,也就是一個AdvisedSupport對象中。
proxyFactory.addAdvisor(advisor); } proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(
this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true);//調用我上面打斷點的那個方法。 } return proxyFactory.getProxy(getProxyClassLoader()); }

現在看看程序是如何獲取與目標對象匹配的advisor的。也就是上述代碼中的specificInterceptors 是如何構建的。

這過程實在是太復雜,看了下源碼,感覺不可能把源碼貼上來結合着講。說下思路吧,目前只看了一遍源碼,可能會有出入的地方:因為advisor是在bean工廠初始化完成的時候就完成了實例化的。所以現在它現將所有用於自動代理的advisor獲取,即不管是不是與目標對象匹配,我先拿過來。然后在進行篩選與目標匹配的advisor。篩選當然是遍歷每一個advisor。在判斷一個advisor是否與目標對象匹配的時候,因為每個advisor都會持有一個切點和一個通知的引用。所以先從advisor中獲取切點對象。然后又通過切點獲取一個ClassFilter對象(每個切點都持有一個ClassFilter對象),也就是說這個ClassFilter間接屬於advisor。ClassFilter,顧名思義,就是拿來過濾的。它有一個的matches(Class<?> clazz)方法。這個方法將目標對象類型作為參數,傳進去匹配。如果相匹配返回true。而這僅僅是類型符合了。但是這個目標類對象中並不是所有的方法后符合啊。

  所以還要判斷目標方法是否符合。所以還需要一個MethodMatcher對象(注:Methodmatcher和ClassFilter都是接口)。MethodMatcher對象也有一個方法叫maches(..)。將目標對象的所有目標方法(Method對象)一個個比較,如果有符合的就返回true。說明advisor和目標對象相符合。

  

 


免責聲明!

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



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