Spring框架之AOP源碼徹底解析html
Spring能夠說是Java企業開發裏最重要的技術。Spring兩大核心IOC(Inversion of Control控制反轉)和AOP(Aspect Oriented Programming面向切面編程)。IOC技術咱們在上一篇文章「Spring框架之beans源碼徹底解析」中進行了分析,本文對Spring框架的AOP源碼進行分析。java
AOP面向切面編程是經過預編譯方式和運行其動態代理,實如今不修改源代碼的狀況下給程序動態統一添加功能的一種技術,是OOP面向對象編程的有效補充。利用AOP技術將日誌記錄,性能統計,安全控制,事務處理,異常處理等代碼從業務邏輯代碼中劃分出來,經過對這些行爲的分離,能夠將它們獨立到非指導業務邏輯的方法中,進而改變這些行爲的時候不會影響業務邏輯的代碼,實現瞭解耦,提升了代碼的靈活性和可擴展性。web
下面就Spring框架的AOP源碼進行解析,主要從如下幾個方面進行剖析:一是對Spring的幾個關鍵概念進行闡述;二是對AOP源碼文件清單進行梳理,一共9大類,204個java文件。三是Spring主要使用JDK動態代理來實現AOP,對JDK動態代理作了一個簡單的介紹。四是結合源碼對Spring AOP的實現原理進行了分析。正則表達式
文章目錄spring
1、Spring AOP幾個關鍵概念express
一、AOP聯盟apache
二、AOP、Spring AOP、AspectJ的區別編程
三、Spring AOP 10個常見概念設計模式
四、Advice(通知/加強)數組
五、Advisor(顧問/加強器)
六、Pointcut(切點)
七、TargetSource(目標對象)
八、Interceptor(攔截器)
2、AOP源碼文件清單
一、aopalliance包含的接口和類
二、AOP包含的接口和類
三、AOP/aspectj包含的接口和類
四、AOP/config包含的接口和類
五、AOP/framework包含的接口和類
六、AOP/interceptor包含的接口和類
七、AOP/scope包含的接口和類
八、AOP/support包含的接口和類
九、AOP/target包含的接口和類
3、JDK動態代理
(一)什麼是代理
(二)Java的動態代理類
(三)動態代理的步驟
4、Spring AOP的實現原理
(一)標籤的解析
(二)獲取加強方法或者加強器
(三)根據獲取的加強建立代理
(四)織入
1、Spring AOP幾個關鍵概念
1、AOP聯盟
AOP聯盟規範了一套用於規範AOP實現的底層API,經過這些統一的底層API,可使得各個AOP實現及工具產品之間實現相互移植。這些API主要以標準接口的形式提供,是AOP編程思想所要解決的橫切交叉關注點問題各部件的最高抽象。Spring的AOP框架中也直接以這些API爲基礎構建。下面咱們來看看當前AOP聯盟發佈的AOP相關的標準接口。
AOP聯盟的API主要包括四個部分,第一個是aop包,定義了一個表示通知Advice的標識接口,各類各樣的通知都繼承或者實現了該接口。aop包中還包括了一個用於描述AOP系統框架錯誤運行時異常AspectException。
第二個部分是intercept包,也就是攔截器包,這個包中規範了AOP核心概念中的鏈接點及通知Advice的類型。
第三部分及第四部分是instrument及reflect包。這兩個包中的API主要包括AOP框架或者產品爲了實現把橫切關注點的模塊和核心應用模塊組合集成,所須要使用的設施、技術及底層實現規範等。
aopalliance1.0.jar類結構以下圖所示(未包括第3、四部分):
aopalliance有三個主要的業務實體:Joinpoint 、Advice、Interceptor。這三個接口構成了aopalliance功能結構。
一、Joinpoint:程序在執行過程當中一個運行時Joinpoint,在這些點關聯的靜態位置一般會安裝有一些Interceptor,當程序運行到這個運行時Joinpoint時,AOP框架會攔截運行時Joinpoint的執行,把運行時Joinpoint交給已經安裝的Interceptor們進行處理。JoinPoint接口有三個方法:
proceed():該方法用於執行攔截器邏輯;
getThis():返回保持當前鏈接點的靜態部分的對象;
getStaticPart():返回此鏈接點的靜態部分(一般包含構造函數,成員變量,方法等信息)
二、Advice只是起到一個超類標記功能。Advice(通知)定義了AOP框架在某個Joinpoint(鏈接點)的通用處理邏輯。
三、Interceptor(攔截器)。Interceptor繼承了Advice,能夠當作是對Advice的特殊功能實現。Interceptor只是Advice處理邏輯中的一種類型或者方式,表示的僅僅是採用攔截處理機制實現了Advice這種功能。
Advice和Interceptor兩個接口沒有任何操做,都是標記接口。(標識接口就是空方法的接口。與其餘接口的區別是:這個接口裏面什麼方法都沒有,只是標記而已。例如serilizeabled就是這樣一個接口,他只是告訴jvm,繼承於這個接口的CLASS須要序列化處理,咱們不用實現這個接口的方法。)
2、AOP、Spring AOP、AspectJ的區別
(1)AOP:Aspect Oriented Programming的縮寫,意爲:面向切面編程,經過預編譯方式和運行期間動態代理實現程序功能的統一維護的一種技術。利用AOP能夠對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度下降,提升程序的可重用性,同時提升了開發的效率。
(2)AspectJ:AspectJ來自於 Eclipse 基金會,屬於靜態植入,它是經過修改代碼來實現的,它的植入時機能夠是:Compile-time weaving編譯期織入;Post-compile weaving編譯後織入,也就是已經生成了.class 文件,或已經達成 jar 包了;Load-time weaving指的是在加載類的時候進行織入。AspectJ 能幹不少 Spring AOP 幹不了的事情,它是 AOP 編程的徹底解決方案。
(3)SpringAOP:它基於動態代理來實現AOP。若是使用接口的,用JDK提供的動態代理實現,若是沒有接口,使用 CGLIB 實現。Spring AOP 致力於解決的是企業級開發中最廣泛的 AOP 需求(方法織入),而不是力求成爲一個像 AspectJ 同樣的 AOP 編程徹底解決方案。
AOP是一種概念,springAOP、AspectJ都是AOP的實現,Spring AOP有本身的語法,可是語法複雜,因此SpringAOP藉助了AspectJ的註解,可是底層實現仍是本身的。
3、Spring AOP 10個常見概念
(1)Joinpoint(鏈接點)
程序執行的某個特定位置,好比某個方法調用前、調用後,方法拋出異常後,對類成員的訪問以及異常處理程序塊的執行等。一個類或一段程序代碼擁有一些具備邊界性質的特定點,這些代碼中的特定點就是鏈接點。它自身還能夠嵌套其餘的Joinpoint。AOP中的Joinpoint能夠有多種類型:構造方法調用,字段的設置和獲取,方法的調用,方法的執行,異常的處理執行,類的初始化。Spring僅支持方法執行類型的Joinpoint。
(2)Pointcut(切點)
若是鏈接點至關於數據中的記錄,那麼切點至關於查詢條件,一個切點能夠匹配多個鏈接點。因此切點表示一組Joinpoint,這些Jointpoint或是經過邏輯關係組合起來,或是經過通配、正則表達式等方式集中起來,它定義了相應的 Advice 將要發生的地方。
(3)Advice(通知/加強)
通知是織入到目標類鏈接點上的一段程序代碼。Spring提供的通知接口都是帶方位名的,如:BeforeAdvice、AfterReturningAdvice、ThrowsAdvice等。咱們經過AOP將橫切關注功能加到原有的業務邏輯上,這是對原有業務邏輯的一種加強,能夠是前置、後置、返回後、拋出異常時等。其實Advice翻譯成「加強」更合理,更能準確表達其本質。既然大部分文獻都是稱爲通知,咱們這裏也稱爲通知。
(4)Introduction(引介)
引介是一種特殊的通知,它爲類添加一些屬性和方法。這樣,即便一個業務類本來沒有實現某個接口,經過引介功能,能夠動態的爲該業務類添加接口的實現邏輯,讓業務類成爲這個接口的實現類。
(5)Interceptor(攔截器)
在Advice的基礎上擴展定義,定義了通知的加強方式,也就是經過對Joinpoint(鏈接點)的攔截。一個通用的攔截器能夠攔截髮生在基礎程序中的運行時事件。
(6)Aspect(切面)
切面是由Pointcut(切點)和Advice(通知)組成的,它包括了對橫切關注功能的定義,也包括了對鏈接點的定義。
(7)Advisor(顧問/加強器)
Advisor是切面的另外一種實現,綁定通知跟切點。沒有指定切點的通知是沒有意義的,Advisor能夠說就是一個綁定在指定切點上的通知。它可以將通知以更爲複雜的方式織入到目標對象中,是將通知包裝爲更復雜切面的裝配器。
(8)TargetSource(目標對象)
包含鏈接點的對象。也被稱做被通知或被代理對象。
(9)Proxy(代理對象)
包含了原始對象的代碼(是在合適的位置調用目標對象的方法)和增長後的代碼(Advice通知的內容)的那個對象。
(10)Weaving(織入)
織入是將Advice通知添加到目標類具體鏈接點上的過程,AOP有三種織入方式:①編譯期織入:須要特殊的Java編譯期(例如AspectJ的ajc);②裝載期織入:要求使用特殊的類加載器,在裝載類的時候對類進行加強;③運行時織入:在運行時爲目標類生成代理實現加強。
AspectJ採用了編譯期織入和裝載期織入的方式,Spring採用了動態代理的方式實現了運行時織入。
4、Advice(通知/加強)
Advice有如下幾種常見的類型:
一、AspectJMethodBeforeAdvice:前置通知。AspectJ中 before 屬性對應的通知(@Before標註的方法會被解析成該通知),在切面方法執行以前執行。
二、AspectJAfterReturningAdvice:後置通知。AspectJ中 afterReturning 屬性對應的通知(@AfterReturning 標註的方法會被解析成該通知),在切面方法執行以後執行,若是有異常,則不執行。注意:該通知與AspectJMethodBeforeAdvice對應。
三、AspectJAroundAdvice:環繞通知。AspectJ中 around 屬性對應的通知(@Around標註的方法會被解析成該通知),在切面方法執行先後執行。
四、AspectJAfterAdvice:返回通知。AspectJ中 after 屬性對應的通知(@After 標註的方法會被解析成該通知),不管是否異常都會執行。
五、AspectJAfterThrowingAdvice:異常通知,AspectJ中 after 屬性對應的通知(@AfterThrowing標註的方法會被解析成該通知),在鏈接點拋出異常後執行。
5、Advisor(顧問/加強器)
advisor:顧問(切面的另外一種實現),封裝了spring aop中的切點和通知。通知(advice)中包含了加強的橫切代碼,切點(pointcut)包含了鏈接點的描述信息。
一、StaticMethodMatcherPointcut:靜態方法切面。定義了一個classFilter,經過重寫getClassFilter()方法來指定切面規則。另外實現了StaticMethodMatcher接口,經過重寫matches來指定方法匹配規則。
二、StaticMethodMatcherPointcutAdvisor:靜態方法匹配切面顧問。擴展了切面排序方法。
三、NameMatchMethodPointcut:名稱匹配切面。經過指定方法集合變量mappedNames,模糊匹配。
四、NameMatchMethodPointcutAdvisor:方法名稱切面顧問。內部封裝了NameMatchMethodPointcut,經過設置方法名稱模糊匹配規則和通知來實現切面功能。
五、RegexpMethodPointcutAdvisor:正則表達式切面顧問。可設置多個正則表達式規則,經過內部封裝的JdkRegexpMethodPointcut解析正則表達式。
六、DefaultPointcutAdvisor:默認切面顧問。比較靈活,可自由組合切面和通知。
七、InstantiationModelAwarePointcutAdvisorImpl:springboot自動裝配的顧問類型。是最經常使用的一種顧問實現。在註解實現的切面中,全部@Aspect類,都會被解析成該對象。
advisorCreator:繼承 spring ioc的擴展接口 beanPostProcessor,主要用來掃描獲取advisor。
一、AbstractAutoProxyCreator:Spring 爲Spring AOP 模塊暴露的可擴展抽象類,也是 AOP 中最核心的抽象類。
二、BeanNameAutoProxyCreator:根據指定名稱建立代理對象。經過設置 advisor,能夠對指定的 beanName 進行代理。支持模糊匹配。
三、AbstractAdvisorAutoProxyCreator:功能比較強大,默認掃描全部Advisor的實現類。相對於根據Bean名稱匹配,該類更加靈活。動態的匹配每個類,判斷是否能夠被代理,並尋找合適的加強類,以及生成代理類。
四、DefaultAdvisorAutoProxyCreator:AbstractAdvisorAutoProxyCreator的默認實現類。能夠單獨使用,在框架中使用AOP,儘可能不要手動建立此對象。
五、AspectJAwareAdvisorAutoProxyCreator:AspectJ的實現方式,也是Spring Aop中最經常使用的實現方式,若是用註解方式,則用其子類AnnotationAwareAspectJAutoProxyCreator。
六、AbstractAutoProxyCreator:Spring 爲Spring AOP 模塊暴露的可擴展抽象類,也是 AOP 中最核心的抽象類。
七、AnnotationAwareAspectJAutoProxyCreator:目前最經常使用的AOP使用方式。spring aop 開啓註解方式以後,該類會掃描全部@Aspect()註釋的類,生成對應的advisor。目前SpringBoot框架中默認支持的方式,自動配置。
6、Pointcut(切點)
一、AnnotationMatchingPointcut:註解匹配切點。根據類上或方法上是否存在指定的註解判斷切點的匹配性,若是沒有顯示指定註解,則匹配全部。
二、DynamicMethodMatcherPointcut:動態方法匹配器切點。它本質上是一個方法匹配器,但同時具備了切點的功能。
三、ComposablePointcut:可組合的切點。這種切點能夠與或邏輯,任意組合其餘的Pointcut、ClassFilter和MethodMatcher。其本質是經過ClassFilters和MethodMatchers兩個工具類進行Pointcut內部組件的組合。
四、JdkRegexpMethodPointcut: JDK正則表達式切點,即便用正則表達式描述方法的攔截規則和排除規則。
五、AspectJExpressionPointcut:AspectJ切點表達式切點。顧名思義,使用AspectJ的切點表達式描述篩選規則。表達式基本語法以下(非完整語法):execution(<方法修飾符>? <方法返回值類型> <包名>.<類名>.<方法名>(<參數類型>) [throws <異常類型>]?)
其中,‘*’表明0個或多個任意字符,包名中的..(兩個點)表明當前包及其子包,參數列表中的..表明任意個參數。如:execution(public static * *..*.*(..) throws *),此表達式匹配全部方法。
7、TargetSource(目標對象)
TargetSource被用於獲取當前MethodInvocation(方法調用)所須要的target(目標對象),這個target經過反射的方式被調用(如:method.invode(target,args))。換句話說,proxy(代理對象)代理的不是target,而是TargetSource。
爲何Spring AOP代理不直接代理target,而須要經過代理TargetSource(target的來源,其內部持有target),間接代理target呢?
一般狀況下,一個proxy(代理對象)只能代理一個target,每次方法調用的目標也是惟一固定的target。可是,若是讓proxy代理TargetSource,可使得每次方法調用的target實例都不一樣(固然也能夠相同,這取決於TargetSource實現)。這種機制使得方法調用變得靈活,能夠擴展出不少高級功能,如:target pool(目標對象池)、hot swap(運行時目標對象熱替換)等等。
TargetSource組件自己與Spring IoC容器無關,target的生命週期不必定是受spring容器管理的,咱們以往的XML中的AOP配置,只是對受容器管理的bean而言的,咱們固然能夠手動建立一個target,同時使用Spring的AOP框架(而不使用IoC容器)
TargetSource包含4個簡單實現和3大類實現。
4個簡單實現包括:
(1)EmptyTargetSource:靜態目標源,當不存在target目標對象,或者甚至連targetClass目標類都不存在(或未知)時,使用此類實例。
(2)HotSwappableTargetSource:動態目標源,支持熱替換的目標源,支持spring應用運行時替換目標對象。
(3)JndiObjectTargetSource:spring對JNDI管理bean的支持,static屬性可配置。
(4)SingletonTargetSource:靜態目標源,單例目標源。Spring的AOP框架默認爲受IoC容器管理的bean建立此目標源。換句話說,SingletonTargetSource、proxy與目標bean三者的聲明週期均相同。若是bean被配置爲prototype,則spring會在每次getBean時建立新的SingletonTargetSource實例。
3大類實現包括:
(1)AbstractBeanFactoryBasedTargetSource:此類目標源基於IoC容器實現,也就是說target目標對象能夠經過beanName從容器中獲取。此類又擴展出:① SimpleBeanTargetSource:簡單實現,直接調用getBean從容器獲取目標對象;② LazyInitTargetSource:延遲初始化目標源,子類可重寫postProcessTargetObject方法後置處理目標對象;③AbstractPrototypeBasedTargetSource:原型bean目標源,此抽象類可確保beanName對應的bean的scope屬性爲prototype。其子類作了簡單原型、池化原型、線程隔離原型這3種實現。
(2)AbstractRefreshableTargetSource:可刷新的目標源。此類實現可根據配置的刷新延遲時間,在每次獲取目標對象時自動刷新目標對象。
(3)AbstractLazyCreationTargetSource:此類實如今調用getTarget()獲取時才建立目標對象
8、Interceptor(攔截器)
Interceptor(攔截器)定義了通知的加強方式,也就是經過對Joinpoint(鏈接點)的攔截。一個通用的攔截器能夠攔截髮生在基礎程序中的運行時事件。這些事件被鏈接點具體化。運行時鏈接點能夠是一次方法調用、字段訪問、異常產生等等。Interceptor接口也在強調概念而非功能,也是一個標記接口。 由Interceptor擴展出的ConstructorInterceptor和MethodInterceptor兩個子接口,才具體定義了攔截方式。它們一個用於攔截構造方法,一個用於攔截普通方法。 可是,spring框架並無支持AOP聯盟對構造方法的攔截,由於spring框架自己,經過BeanPostProcessor的定義,對bean的生命週期擴展已經很充分了。
MethodInterceptor只定義了加強方式,咱們能夠經過實現此接口,自定義具體的加強內容。固然,spring框架也提供了3種預約義的加強內容:BeforeAdvice(前置通知)、AfterAdvice(後置通知)和DynamicIntroductionAdvice(動態引介通知)。BeforeAdvice和AfterAdvice更確切地說是定義了加強內容的執行時機(方法調用以前仍是以後);而DynamicIntroductionAdvice比較特殊,它能夠編輯目標類要實現的接口列表。最後,spring預約義的通知仍是要經過對應的適配器,適配成MethodInterceptor接口類型的對象(如:MethodBeforeAdviceInterceptor負責適配MethodBeforeAdvice)。
幾個經常使用攔截器:
(1)MethodBeforeAdviceInterceptor:MethodBeforeAdvice(前置通知,其父接口是BeforeAdvice)接口的適配器,用於支持spring預約義的前置通知,在目標方法調用前調用MethodBeforeAdvice.before()。
(2)AspectJAfterAdvice :AspectJ框架的後置通知實現,在目標方法執行結束後,return以前,調用配置指定的方法(注意:此方法調用被寫在finally塊中,不管如何都會獲得執行)。
(3)AfterReturningAdviceInterceptor :AfterReturningAdvice接口的適配器,用於支持spring預約義的後置通知,在目標方法執行結束後,return以前,調用AfterReturningAdvice.afterReturning()執行(注意:若是目標方法拋出異常,則不會執行這個方法)。
(4)AspectJAfterThrowingAdvice :AspectJ框架的異常通知,當目標方法執行時產生異常的時候,指定配置指定的方法。
(5)AspectJAroundAdvice :AspectJ框架的環繞通知,直接執行配置指定的方法。
(6)ThrowsAdviceInterceptor :spring框架預約義的異常通知的適配器,此適配器接受任意類型的對象,可是要求對象所在類必須聲明public的名稱爲afterThrowing,且參數個數爲1個或4個,且最後一個參數爲Throwable類型的方法。該適配器會保存該Throwable對象的實際類型到該方法之間的映射,當目標方法執行產生異常時,根據產生的異常類型找到對應的通知方法進行調用。
(7)DelegatingIntroductionInterceptor:經過構造方法傳入指定的引介對象,每當調用的目標方法是引介接口定義的方法時,都會調用該引介對象的對應方法。
(8)DelegatePerTargetObjectIntroductionInterceptor:經過構造函數傳入指定的引介接口和接口對應的實現類,該攔截器會爲每一個目標對象建立新的引介對象(經過調用實現類的默認無參構造)。當調用的方法是引介接口定義的方法時,則調用該新建的引介對象對應的方法。
2、AOP源碼文件清單
本文進行梳理的AOP源碼文件清單是基於版本號爲5.2.4.BUILD-SNAPSHOT的Spring源碼。一共9大類,204個java文件。
1、aopalliance
aopalliance/aop
1.1 Advice:定義了一個表示通知的標識接口,各類各樣的通知都繼承或實現了該接口。
1.2 AspectException:描述AOP系統框架錯誤的運行時異常。
aopalliance/intercept
1.3 Joinpoint:鏈接點。在攔截器中使用,封裝了原方法調用的相關信息,如參數、原對象信息,以及直接調用原方法的proceed方法。
1.4 Invocation 運行時的方法調用,繼承自joinpoint。
1.5 ConstructorInvocation:Invocation的子類,包含了獲取構造器的方法。
1.6 MethodInvocation:Invocation的子類,返回被調用的方法信息。
1.7 Interceptor:攔截器,Advice的子接口,標記攔截器。攔截器是加強器的一種。
1.8 ConstructorInterceptor:構造器攔截器,Interceptor的子接口,攔截構造器並處理。
1.9 MethodInterceptor:方法攔截器,Interceptor的子接口,攔截方法並處理,核心類。
2、AOP
2.1 Pointcut:切點的一個頂層抽象。切點的主要做用是定義通知所要應用到的類跟方法。具體的哪些類、哪些方法由ClassFilter和MethodMatcher匹配,只有知足切入點的條件時才插入advice。
2.2 TruePointcut:Pointcut(切點)接口的一個最簡單的實現類,匹配到全部。
2.3 AfterAdvice:不管一個 join point 是正常退出仍是發生了異常, 都會被執行的 advice。
2.4 AfterReturningAdvice:後置通知(After Returning Advice)後置通知相比較於前置通知,主要有如下幾點不一樣:後置通知能夠訪問目標方法的返回值,可是不能修改,後置通知是在方法執行完成後執行。
2.5 BeforeAdvice:在 join point 前被執行的 advice。雖然 before advice 是在 join point 前被執行,可是它並不可以阻止 join point 的執行,除非發生了異常(即咱們在 before advice 代碼中, 不能人爲地決定是否繼續執行 join point 中的代碼)。
2.6 MethodBeforeAdvice:前置通知(Before Advice)跟環繞通知不一樣的是,這個接口中定義的方法的返回值是void,因此前置通知是沒法修改方法的返回值的。若是在前置通知中發生了異常,那麼會直接終止目標方法的執行以及打斷整個攔截器鏈的執行。
2.7 ThrowsAdvice:異常通知(Throws Advice),其中沒有定義任何方法,它更像一個標記接口。咱們在定義異常通知時須要實現這個接口,同時方法的簽名也有要求:一、方法名稱必須是afterThrowing。二、方法的參數個數必須是1個或者4個。
2.8 Advisor:顧問,封裝了spring aop中的切點和通知。 就是咱們經常使用的@Aspect 註解標記的類。
2.9 PointcutAdvisor:表明具備切點的切面,它包含Advice和Pointcut兩個類,這樣就能夠經過類、方法名以及方法方位等信息靈活地定義切面的鏈接點,提供更具適用性的切面。其有6種實現類:
DefaultPointcutAdvisor:最經常使用的切面類型,它能夠經過任意Pointcut和Advice定義一個切面,惟一不支持的是引介的切面類型,通常能夠經過擴展該類實現自定義的切面;
NameMatchMethodPointcutAdvisor:經過該類能夠定義,按方法名定義切點的切面;
RegexpMethodPointcutAdvisor:按正則表達式匹配方法名進行切點定義的切面;
StaticMethodMatcherPointcutAdvisor:靜態方法匹配器切點定義的切面;
AspecJExpressionPointcutAdvisor:Aspecj切點表達式定義切點的切面;
AspecJPointcutAdvisor:使用AspecJ語法定義切點的切面。
2.10 MethodMatcher:用來匹配方法。MethodMatcher中一共有三個核心方法:
matches(Method method, @Nullable Class<?> targetClass),這個方法用來判斷當前定義的切點跟目標類中的指定方法是否匹配,它能夠在建立代理的時候就被調用,從而決定是否須要進行代理,這樣就能夠避免每次方法執行的時候再去作判斷。
isRuntime(),若是這個方法返回true的話,意味着每次執行方法時還須要作一次匹配。
matches(Method method, @Nullable Class<?> targetClass, Object... args),當以前的isRuntime方法返回true時,會調用這個方法再次進行一次判斷,返回false的話,意味着不對這個方法應用通知。
接口的實現類有不少,如StaticMethodMatcher(只支持靜態匹配,兩個參數的matchs)、AspectJExpressionPointcut(AOP重要組件)、TrueMethodMatcher(老是匹配)、AnnotationMethodMatcher(註解匹配)。
2.11 TrueMethodMatcher:MethodMatcher接口的一個最簡單的實現類,匹配到全部的方法。
2.12 ClassFilter:主要做用是在類級別上對通知的應用進行一次過濾,若是它的match方法對任意的類都返回true的話,說明在類級別上咱們不須要過濾,這種狀況下,通知的應用,就徹底依賴MethodMatcher的匹配結果。ClassFilter有4中簡單方式的實現:
(1)TypePatternClassFilter:基於AspectJ的類型匹配實現;
(2)AnnotationClassFilter:經過檢查目標類是否存在指定的註解,決定是否匹配;
(3)RootClassFilter:經過判斷目標類是不是指定類型(或其子類型),決定是否匹配;
(4)TrueClassFilter:這是最簡單實現,matches方法總會返回true。此類設計使用了單例模式,且其對象引用直接被在ClassFilter接口中聲明成了常量。
2.13 TrueClassFilter:ClassFilter接口的一個最簡單的實現類,匹配到全部的類。
2.14 IntroductionInfo:描述一個引介須要的基本信息。引介(Introduction)是指在不更改源代碼的狀況,給一個現有類增長屬性、方法,以及讓現有類實現其它接口或指定其它父類等,從而改變類的靜態結構。是另外一種類型的加強,和通知是並列的兩種不一樣的加強。
2.15 IntroductionAdvisor:advisor顧問,封裝了spring aop中的切點和通知。這個接口是用來處理一個或者多個引入的顧問的父接口。
2.16 DynamicIntroductionAdvice:引介通知(Introduction Advice)。
2.17 IntroductionAwareMethodMatcher:繼承自MethodMatcher,在進行方法匹配時考慮了引入。
2.18 IntroductionInterceptor:AOP聯盟中的MethodInterceptor(方法攔截器,攔截方法並處理)的子接口。
2.19 TargetSource:TargetSource(目標源)是被代理的target(目標對象)實例的來源。
2.20 TargetClassAware:在代理中用來公開目標類的最小接口,主要被代理對象和代理工廠所實現.。全部的Aop代理對象或者代理工廠(proxy factory)都要實現的接口,該接口用於暴露出被代理目標對象類型。
2.21 RawTargetAccess:AOP代理的標記接口,用來返回原始的目標對象。
2.22 SpringProxy:標記接口,Spring使用JDK動態代理或者CGLIB的方式來生成代理對象,其中每一個代理對象都會實現SpringProxy接口。用來斷定是不是Spring產生的代理對象。
2.23 ProxyMethodInvocation:MethodInvocation接口的拓展,可以返回一個代理對象,而當前的Method Invocation是經過該代理對象辦到的。
2.24 AopInvocationException:由於錯誤的配置或者始料不及的運行時出現的問題,致使AOP運行時方法調用失敗時拋出的異常。
3、AOP/aspectj
3.1 AbstractAspectJAdvice:AOP基類,用來包裝AspectJ切面(AspectJ aspect)或AspectJ註解(AspectJ-annotated)的通知方法。
3.2 AspectJAfterAdvice:返回通知,AspectJ中 after 屬性對應的通知(@After 標註的方法會被解析成該通知),不管是否異常都會執行。
3.3 AspectJAfterReturningAdvice:後置通知,AspectJ中 afterReturning 屬性對應的通知(@AfterReturning 標註的方法會被解析成該通知),在切面方法執行以後執行,若是有異常,則不執行。注意:該通知與AspectJMethodBeforeAdvice對應。
3.4 AspectJMethodBeforeAdvice:前置通知,AspectJ中 before 屬性對應的通知(@Before標註的方法會被解析成該通知),在切面方法執行以前執行。
3.5 AspectJAfterThrowingAdvice:異常通知,AspectJ中 after 屬性對應的通知(@AfterThrowing標註的方法會被解析成該通知),在鏈接點拋出異常後執行。
3.6 AspectJAroundAdvice:環繞通知,AspectJ中 around 屬性對應的通知(@Around標註的方法會被解析成該通知),在切面方法執行先後執行。
3.7 AspectJPointcutAdvisor:繼承自接口PointcutAdvisor,該類用來調整AbstractAspectJAdvice 使其適應PointcutAdvisor接口 。
3.8 AspectJExpressionPointcutAdvisor:用來處理對應 AspectJ 的 advice 和切點的,有advice的設置和獲取、切點表達式的一些處理、設置切點的Bean工廠,獲取該切點等方法。該類建立了一個 AspectJExpressionPointcut,它們之間的關係是一對一的組合關係。
3.9 DeclareParentsAdvisor:Spring AOP提供的@Before、@After、@AfterReturning、@AfterThrowing、@Around只對類的現有方法進行加強處理。若是須要對現有類增長新的方法,有兩種方法可實現:(1)擴展示有類:實現簡單,但若是對多個現有類進行擴展時,需增長多個類。(2)使用@DeclareParents註解實現:實現複雜,可以使用通配符匹配。
3.10 InstantiationModelAwarePointcutAdvisor:由spring aop顧問實現的接口,封裝了可能具備延遲初始化策略的AspectJ 切面。
3.11 AspectJExpressionPointcut:AspectJ表達式切點(經過解析XML配置文件中的<aop:pointcut>元素生成的就是此類型的bean)。它是一種切點,但與通常的切點不一樣,通常的切點須要持有單獨的ClassFilter和MethodMatcher。可是AspectJ表達式切點自己就兼具了這兩個組件的功能。由於切點表達式,就是用來描述要代理的目標類和目標方法的。
3.12 MethodInvocationProceedingJoinPoint:AspectJ的ProceedingJoinPoint接口的一個實現類,包裝了MethodInvocation。Proceedingjoinpoint接口 繼承自 JoinPoint,是在JoinPoint的基礎上暴露出 proceed 這個方法。環繞通知=前置+目標方法執行+後置通知,proceed方法就是用於啓動目標方法執行的,暴露出這個方法,就能支持 aop:around 這種切面。
3.13 AspectInstanceFactory:切面工廠,實現該接口的工廠用來生成AspectJ切面的一個實例。
3.14 SimpleAspectInstanceFactory:該接口主要用於從給定的類(或者 beanName 等)獲取一個切面實例,這是AspectInstanceFactory接口的一個實現類。
3.15 SingletonAspectInstanceFactory:AspectInstanceFactory接口的一個實現類,用來支持單例的對象,對於每次調用getAspectInstance(),都返回同一個切面實例。
3.16 AspectJAopUtils:相比於AopUtils,AspectJAopUtils是專門針對於AspectJ advisors的工具類。
3.17 AspectJProxyUtils:它相對於AopProxyUtils,它只是專門處理AspectJ代理對象的工具類。
3.18 AspectJAdviceParameterNameDiscoverer:從切點表達式、返回值、拋出異常來推斷一個AspectJ通知方法的參數名,若是不存在一個明確的推斷,返回Null。
3.19 AspectJPrecedenceInformation:存儲用來給通知、顧問根據AspectJ的排序規則進行排序用的相關信息。
3.20 AspectJWeaverMessageHandler:實現自AspectJ的IMessageHandler接口,與常規Spring消息同樣,使用相同的日誌系統來對AspectJ編織消息進行路由。
3.21 RuntimeTestWalker:這個類用來封裝一些AspectJ內部的結果,在未來解壓中再從新推送到AspectJ項目中。
3.22 TypePatternClassFilter:ClassFilter類過濾器。基於AspectJ的類型匹配實現。
AOP/aspectj/annotation
3.23 AspectJAdvisorFactory:該類主要用於對切面的校驗,從切面中解析 Advisor, Advice 等。
3.24 AbstractAspectJAdvisorFactory:做爲父類完成了 是否切面、切面校驗、方法切面註解獲取、切面註解封裝、切面參數解析等一些列工做,將核心的解析 Advisors Advice 交給了 ReflectiveAspectJAdvisorFactory。
3.25 ReflectiveAspectJAdvisorFactory:獲取 Advisors,從 MetadataAwareAspectInstanceFactory (包含有切面的元數據信息)中獲取切面元數據信息,將方法切點解析爲對應的 AspectJExpressionPointcut(經過切點表達式),而後封裝成 InstantiationModelAwarePointcutAdvisorImpl 返回。
3.26 AspectJProxyFactory:建立AspectJ的AOP對象,用於Spring集成AspectJ的做用,此時,就不須要使用AspectJ特定的編譯器了。
3.27 MetadataAwareAspectInstanceFactory:AspectInstanceFactory的子接口,返回與AspectJ annotated相關的AspectMetedata。原本AspectInstanceFactory包含該方法是最好的,可是AspectMetedata僅僅使用Java 5,因此咱們須要單獨分離出該子接口。
3.28 LazySingletonAspectInstanceFactoryDecorator:簡單的裝飾,使MetadataAwareAspectInstanceFactory實例化一次。
3.29 SingletonMetadataAwareAspectInstanceFactory:MetadataAwareAspectInstanceFactory的一個實現類,每次調用getAspectInstance()函數時,都會返回同一個實例。
3.30 BeanFactoryAspectInstanceFactory:該類就是AspectInstanceFactory接口的一個實現類,用來生成AspectJ切面的一個實例。須要注意的是若是使用原型模式,實例化屢次,可能返回的不是你想要的。使用LazySingletonAspectInstanceFactoryDecorator包裝該類,這樣就能夠確保每次均可以獲得一個新的切面實例。
3.31 PrototypeAspectInstanceFactory:多例專用的工廠。
3.32 SimpleMetadataAwareAspectInstanceFactory:MetadataAwareAspectInstanceFactory的一個實現類,每次調用getAspectInstance()函數時,都會建立指定的切面類的實例。
3.33 AspectMetadata:AspectJ切面類的元數據,每一個切面附加一個額外的Spring AOP切點。該類有屬性:aspectName、aspectClass、ajType(transient修飾,表示該屬性不須要序列,序列化對象的時候,這個屬性就不會被序列化)、perClausePointcut。
3.34 InstantiationModelAwarePointcutAdvisorImpl:AspectJPointcutAdvisor的內部實現,注意對於每個目標方法都會有一個該顧問的實例。
3.35 BeanFactoryAspectJAdvisorsBuilder: Spring AOP內部工具類,用來從bean容器也就是BeanFactory中獲取全部使用了@AspectJ註解的bean,最終用於自動代理機制(auto-proxying)。
該工具內部使用了緩存機制,雖然公開的查找方法可能會被調用屢次,但並非每次都會真正查找,而是會利用緩存。最核心的邏輯在其方法buildAspectJAdvisors中,該方法查找容器中全部@AspectJ註解的bean,而後將其中每一個advice方法包裝成一個Spring Advisor。最終結果以一個List<Advisor>的形式返回給調用者。
3.36 AnnotationAwareAspectJAutoProxyCreator:目前最經常使用的AOP使用方式。spring aop 開啓註解方式以後,該類會掃描全部@Aspect()註釋的類,生成對應的advisor。目前SpringBoot框架中默認支持的方式,自動配置。
3.37 NotAnAtAspectException:AopConfigException類的拓展,當試圖對一個類生成顧問,可是該類又不是AspectJ 註解類型的切面的時候拋出異常。
AOP/aspectj/autoproxy
3.38 AspectJAwareAdvisorAutoProxyCreator:AspectJ的實現方式,也是Spring Aop中最經常使用的實現方式,若是用註解方式,則用AnnotationAwareAspectJAutoProxyCreator(該類的一個子類)。
3.39 AspectJPrecedenceComparator:排序比較器。它優先比較兩個加強器所屬的切面大小,若是是同一個切面產生的兩個加強器,他們的大小是相同的,則須要拿到它們的聲明順序即InstantiationModelAwarePointcutAdvisorImpl的declarationOrder屬性。
4、AOP/config
4.1 PointcutComponentDefinition:建立一個切點的信息。
4.2 AspectComponentDefinition:建立一個切面的信息,包括了嵌套的切點。
4.3 AdvisorComponentDefinition:建立一個顧問的信息,用來彌合經過<aop:advisor>配置的顧問的bean definition和架構中的部件定義。
4.4 AbstractInterceptorDrivenBeanDefinitionDecorator:BeanDefinitionDecorator(接口)裝飾相關的自定義屬性。該抽象類繼承自BeanDefinitionDecorator,用於註冊相應的Interceptor bean 定義。
4.5 ScopedProxyBeanDefinitionDecorator:<aop:scoped-proxy>標籤是spring<bean>標籤的裝飾標籤,AOP命名空間的三大標籤之一,它的做用是對生命週期短的bean提供裝飾,使其能被生命週期長的bean正確調用。該類負責對該標籤進行解析。
4.6 PointcutEntry:實現了接口ParseState.Entry,表明一個切點的入口。
ParseState(在包org.springframework.beans.factory.parsing中)在解析進程中做爲一個簡單的基於棧結構的追蹤邏輯位置類。該類中有一個內部標記接口Entry,爲了進入ParseState,要實現該內部標記接口。
4.7 AdviceEntry:實現了接口ParseState.Entry,表明一個通知的入口。
4.8 AdvisorEntry:實現了接口ParseState.Entry,表明一個顧問的入口。
4.9 AspectEntry:實現了接口ParseState.Entry,表明一個切面的入口。
4.10 SpringConfiguredBeanDefinitionParser:實現了接口BeanDefinitionParser,專門用來解析<aop:spring-configured/>標籤。
4.11 AspectJAutoProxyBeanDefinitionParser:是一個實現了BeanDefinitionParser接口的類,專門用於解析切面自動代理的Bean定義的解析工做,重點在其parse方法。
4.12 ConfigBeanDefinitionParser:用來解析<aop:config />標籤,並將標籤相應的BeanDefinition註冊BeanFactory(DefaultListableBeanFactory)。
4.13 AopConfigUtils:這個是關於AOP配置的工具類。由於配置AOP的方式有多種(好比xml、註解等),此工具類就是針對不一樣配置,提供不一樣的工具方法的。它的好處是無論什麼配置,最終走底層邏輯都歸一了。
4.14 AopNamespaceHandler:AOP命名空間處理器,Spring爲了開放性提供了NamespaceHandler機制,這樣咱們就能夠根據需求本身來處理咱們設置的標籤元素。咱們使用基於xml的spring配置時,可能須要配置如<aop:config />這樣的標籤,在配置這個標籤以前,一般咱們須要引入這個aop所在的命名空間。只有經過配置aop的命名空間纔會找到AOP標籤的處理器AopNamespaceHandler,在AOP的jar中的spring.handlers配置文件中配置了命名空間和命名空間處理器之間的關係。
4.15 AopNamespaceUtils:處理Spring AOP命名空間的工具類。
4.16 MethodLocatingFactoryBean:實現了FactoryBean接口,經過調用getObject()方法獲取MethodLocatingFactory對象。主要做用是經過Bean的名稱和方法名定位到這個Method,而後經過反射進行調用。
4.17 SimpleBeanFactoryAwareAspectInstanceFactory:繼承自AspectInstanceFactory(切面實例工廠),該類在bean工廠中經過bean的名字能夠定位到切面。
5、AOP/framework
5.1 AopProxy:表明一個AopProxy代理對象,能夠經過這個對象構造代理對象實例。
5.2 AopProxyUtils:對org.springframework.aop.support.AopUtils的一個補充。其中比較重要的方法: completeProxiedInterfaces(判斷一個advised真正須要代理的目標接口列表 )和ultimateTargetClass(獲取一個代理對象的最終對象類型)。
5.3 ProxyConfig:AOP配置類,是全部的AOP代理工廠的父類,它包含了建立一個AOP代理所須要的基礎的通用的一些配置信息。它有五個屬性:
proxyTargetClass 是否直接對目標類進行代理,而不是經過接口產生代理;
optimize 標記是否對代理進行優化;
opaque 標記是否須要阻止經過該配置建立的代理對象轉換爲Advised類型;
exposeProxy 標記代理對象是否應該被aop框架經過AopContext以ThreadLocal的形式暴露出去;
frozen 標記是否須要凍結代理對象,即在代理對象生成以後,是否容許對其進行修改。
5.4 ProxyProcessorSupport:提供爲代理建立器提供了一些公共方法實現。
5.5 ProxyCreatorSupport:這個類的主要做用是爲建立一個AOP代理對象提供一些功能支持,經過它的getAopProxyFactory能獲取一個建立代理對象的工廠。
5.6 ProxyFactory:ProxyFactory繼承自ProxyCreatorSupport,使用它來建立一個代理對象也是要先去設置相關的配置信息,而後再調用建立代理的方法。
5.7 ProxyFactoryBean:ProxyFactoryBean的功能:初始化通知器鏈,獲取單例、原型的Aop代理對象。
5.8 AbstractSingletonProxyFactoryBean:FactoryBean的一個超類,主要用來生成singleton-scoped代理對象。
5.9 AopProxyFactory:AopProxy代理工廠類,用於生成代理對象AopProxy。
5.10 DefaultAopProxyFactory AopProxyFactory:AopProxyFactory默認實現類,核心函數createAopProxy。
5.11 JdkDynamicAopProxy:生成jdk動態代理。能夠看到這個類自己就是一個InvocationHandler,這意味着當調用代理對象中的方法時,最終會調用到JdkDynamicAopProxy的invoke方法。
5.12 CglibAopProxy:生成Cglib動態代理。
5.13 ObjenesisCglibAopProxy :該類繼承自CglibAopProxy,重寫了createProxyClassAndInstance方法。
objenesis是一個小型Java類庫用來實例化一個特定class的對象。Java已經支持使用class.newinstance()的類動態實例化,可是必需要有一個合適的構造函數。而不少場景下類不可以用這種方式去實例化,例如:構造函數須要參數(Constructors that require arguments)、有反作用的構造函數(Constructors that have side effects)、會拋出異常的構造函數(Constructors that throw exceptions)。
所以,常見的是在類庫中看到類必需要有一個默認的構造函數的限制,Objenesis旨在經過繞過對象實例化的構造函數來克服這些限制。典型用途:(1)序列化,遠程調用和持久化-對象須要被實例化並恢復到特定的狀態,而不須要調用代碼。(2)代理、 AOP 庫和 mock 對象-類能夠被子類繼承而子類不用擔憂父類的構造器。(3)容器框架-對象能夠以非標準的方式動態地實例化。
5.14 Advised:表明被Advice加強的對象,包括添加advisor的方法、添加advice等的方法。
5.15 AdvisedSupport:ProxyConfig類的子類,封裝了AOP中通用的對加強(Advice)和通知器(Advisor)的相關操做,對於全部生成AOP代理對象都通用,而代理對象的生成由子類完成。
5.16 AdvisedSupportListener:監聽器,註冊在ProxyCreatorSupport對象(用來註冊和觸發監聽器)中,捕獲第一個代理建立時和代理建立後通知狀態發生改變的事件。
5.17 AopInfrastructureBean:免被AOP代理的標記接口。是一個標記接口。若Bean實現了此接口,代表它是一個Spring AOP的基礎類,那麼這個類是不會被AOP給代理的,即便它能被切面切進去。
5.18 AbstractAdvisingBeanPostProcessor:繼承自BeanPostProcessor,自身內置一個 Advisor,檢查當前bean是否符合應用該 Advisor 的條件,符合的話將本身的 Advisor 包裹到當前bean(必要的時候爲當前bean建立代理對象以便包裹本身的Advisor)。其中調用了函數AopUtils.canApply(this.advisor, targetClass),用來檢查某個 Advisor 是否可應用到某個 bean 上的。
5.19 AopConfigException:AOP配置參數非法時拋出的異常。
5.20 AopContext:表明AOP的上下文。主要是提供咱們訪問上下文中當前AOP對象的快速方法。
5.21 AdvisorChainFactory:獲取加強器鏈的工廠接口。提供方法返回全部加強器,以數組返回。
5.22 DefaultAdvisorChainFactory:這個工廠類負責生成攔截器鏈。藉助DefaultAdvisorAdapterRegistry將Advisor集合轉換成MethodInterceptor集合。
5.23 InterceptorAndDynamicMethodMatcher:框架的內部類,組合MethodInterceptor實例和MethodMatch做爲加強器鏈中的一個元素。
5.24 ReflectiveMethodInvocation:核心類,激發攔截鏈工做實現。該類實現了aop聯盟的MethodInvocation,間接實現了Invocation和Joinpoint。
AOP/framework/adapter
5.25 AdvisorAdapter:一個適配器接口,它定義了本身支持的Advice類型,而且能把一個Advisor適配成MethodInterceptor。
spring aop框架對BeforeAdvice、AfterAdvice、ThrowsAdvice三種通知類型的支持其實是藉助適配器模式來實現的,這樣的好處是使得框架容許用戶向框架中加入本身想要支持的任何一種通知類型。
5.26 AdvisorAdapterRegistry:顧問適配器註冊的接口,這是一個SPI接口,不會被任何Spring用戶所實現。java spi就是提供這樣的一個機制:爲某個接口尋找服務實現的機制。
5.27 DefaultAdvisorAdapterRegistry:它用來完成各類通知的適配和註冊過程。將Advice包裝成Advisor(DefaultPointCutAdvisor),藉助AdvisorAdapter,將Advisor包裝成MethodInterceptor。
5.28 GlobalAdvisorAdapterRegistry:負責攔截器的適配和註冊過程。
5.29 AdvisorAdapterRegistrationManager:繼承自BeanPostProcessor後置處理器,利用AdvisorAdapterRegistry在Bean工廠中註冊AdvisorAdapter(通知適配器)。
5.30 AfterReturningAdviceAdapter:後置通知適配器。
在 Spring 的 Aop 中,適配器模式應用的很是普遍。Spring 使用 Advice(通知)來加強被代理類的功能,Advice 的類型主要有 BeforeAdvice、AfterReturningAdvice、ThrowsAdvice。每種 Advice 都有對應的攔截器,即 MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor。各類不一樣類型的 Interceptor,經過適配器統一對外提供接口。最終調用不一樣的 advice來實現被代理類的加強。
5.31 AfterReturningAdviceInterceptor:後置通知攔截器。
5.32 MethodBeforeAdviceAdapter:前置通知適配器。
5.33 MethodBeforeAdviceInterceptor:前置通知攔截器。
5.34 ThrowsAdviceAdapter:異常通知適配器。
5.35 ThrowsAdviceInterceptor:異常通知攔截器。
5.36 UnknownAdviceTypeException:當嘗試使用一個不支持的顧問或者通知時拋出的異常。
AOP/framework/autoproxy
5.37 AbstractAdvisorAutoProxyCreator:默認掃描全部Advisor的實現類,相對於根據Bean名稱匹配,該類更加靈活。動態的匹配每個類,判斷是否能夠被代理,並尋找合適的加強類,以及生成代理類。
5.38 AbstractAutoProxyCreator:Spring 爲Spring AOP 模塊暴露的可擴展抽象類,也是 AOP 中最核心的抽象類。自動代理機制的實現其實很簡單,就是經過Bean的後置處理器,在建立Bean的最後一步對Bean進行代理,並將代理對象放入到容器中。實現自動代理的核心類就是AbstractAutoProxyCreator。
它的三個具體的實現類來進行分析,分別是BeanNameAutoProxyCreator、DefaultAdvisorAutoProxyCreator、AnnotationAwareAspectJAutoProxyCreator。
5.39 BeanNameAutoProxyCreator:根據指定名稱建立代理對象。經過設置 advisor,能夠對指定的 beanName 進行代理。支持模糊匹配。
5.40 DefaultAdvisorAutoProxyCreator:AbstractAdvisorAutoProxyCreator的默認實現類。能夠單獨使用,在框架中使用AOP,儘可能不要手動建立此對象。
5.41 InfrastructureAdvisorAutoProxyCreator :自動代理建立器,全部的建立器都是AbstractAutoProxyCreator抽象類的子類。該類是Spring給本身內部使用的一個自動代理建立器。它主要是讀取Advisor類,並對符合的bean進行二次代理。
5.42 AutoProxyUtils:爲自動代理組件準備的工具類。主要用於框架內部使用(AbstractAutoProxyCreator)。
5.43 ProxyCreationContext:當前代理建立的上下文,主要給自動代理建立器使用。好比AbstractAdvisorAutoProxyCreator。
5.44 AbstractBeanFactoryAwareAdvisingPostProcessor:該抽象類定義了這樣一類BeanPostProcessor:擁有一個Advisor,對每一個bean進行後置處理,若是該bean符合包裹本身所擁有的Advisor的條件,則將該Advisor包裹該bean。
這裏將bean和Advisor包裹該bean的又分兩種狀況:目標bean是Advised,此時直接使用Advised接口定義的方法添加Advisor到目標bean。目標bean不是Advised,此時爲目標對象建立代理對象,並將Advisor添加到目標bean的代理對象上。
以上主要邏輯基本實如今其父類AbstractAdvisingBeanPostProcessor 中,而該類主要是在此基礎上實現了BeanFactoryAware接口。並覆蓋實現父類的方法prepareProxyFactory,isEligible。
5.45 BeanFactoryAdvisorRetrievalHelper:這個類很重要,是一個Spring AOP內部工具類,用來從bean容器(BeanFactory)中獲取全部Spring的Advisor bean(這裏的 Spring Advisor bean指的是實現了接口org.springframework.aop.Advisor的bean)。是真正去容器中找出全部的Advisor的類。該工具內部使用了緩存機制,雖然公開的查找方法可能會被調用屢次,但並非每次都會真正查找,而是會利用緩存。
5.46 TargetSourceCreator:建立專用的target source。
AOP/framework/autoproxy/target
5.47 AbstractBeanFactoryBasedTargetSourceCreator:TargetSourceCreator的一個超類,對於一個原型bean須要建立多個實例時使用。使用一個內部的bean工廠去管理這些target實例。
5.48 LazyInitTargetSourceCreator:建立的代理對象並無初始化,直到第一次調用時才進行初始化。
5.49 QuickTargetSourceCreator:根據beanName的不一樣前綴建立三種經常使用的TargetSource類型(bean必須爲多例)。(1)CommonsPoolTargetSource:池化TargetSource,每次執行方法時從池中取代理對象,執行完方法再返回池中。(2)ThreadLocalTargetSource:線程級的TargetSource。(3)PrototypeTargetSource:多例TargetSource,每次執行方法建立新的代理對象,執行完銷燬該對象。
6、AOP/interceptor
6.1 AbstractTraceInterceptor:MethodInterceptor的實現類,主要用於日誌記錄。默認狀況下,寫入日誌中的消息是記錄攔截器類而不是被攔截的類。當把bean屬性開關useDynamicLogger設置爲true時,攔截器類和被攔截的類日誌都會被記錄下來。該抽象類的實現子類必須實現方法invokeUnderTrace。
6.2 SimpleTraceInterceptor:繼承自AbstractTraceInterceptor, 該攔截器能夠引入攔截器鏈中,用來顯示被攔截的方法調用的詳細跟蹤信息,包括方法進入和退出的信息。 若是想要更高級的需求,能夠考慮使用自定義的跟蹤攔截器CustomizableTraceInterceptor。
6.3 CustomizableTraceInterceptor:方法級示蹤器。 MethodInterceptor的實現類,使用佔位符,來進行自定義的方法層級的示蹤器。跟蹤在方法入口處消息是否寫入,在方法退出時判斷方法調用是否成功。若是調用出現異常,那麼一個異常消息記錄下來。這些跟蹤消息和佔位符是高度定製化的,你能夠將一些運行時信息寫入日誌系統中。
6.4 DebugInterceptor:這個攔截器能夠引入鏈中用來將攔截的調用的一些詳細信息顯示到日誌記錄器中。在進行調試時,能夠將方法入口和出口處的一些調用細節詳細的記錄下來,包括調用的參數和調用的次數。
6.5 ExposeInvocationInterceptor:暴露當前MethodInvocation的攔截器。做爲線程本地對象, 咱們偶爾須要這樣作, 好比切入點時須要知道完整的調用上下文。除非確實有必要,不然不要使用此攔截器。 目標對象應該一般不瞭解Spring AOP,由於這會產生對Spring API的依賴。目標對象應儘量是普通的POJO。若是要使用這個攔截器,要將這個攔截器放在攔截鏈中的開頭。
6.6 AbstractMonitoringInterceptor:監控攔截器的基類,好比性能監控器。
6.7 PerformanceMonitorInterceptor:性能監控的攔截器,這個攔截器對於被攔截的方法不會有任何附加的做用。其在實際的性能測量時,使用了簡潔的耗時統計小工具org.springframework.util.StopWatch。
6.8 JamonPerformanceMonitorInterceptor:性能監控的攔截器,使用了JAMon庫對被攔截的方法和輸出的狀態信息進行性能的監測。另外它也能夠對被攔截的方法拋出的異常進行跟蹤計數,這些堆棧跟蹤足跡能夠在JAMopn的web應用中顯示出來。
Jamon的全名是:Java Application Monitor。它是一個小巧的,免費的,高性能的,線程安全的性能監測工具。它能夠用來測定系統的性能瓶頸,也能夠用來監視用戶和應用程序之間的交互狀況。 Jamon主要是用來檢測jee的應用程序。
6.9 ConcurrencyThrottleInterceptor:繼承自ConcurrencyThrottleSupport,spring控制併發數的工具類。在ConcurrencyThrottleSupport類中,簡單的經過synchronized和wati and notify達到控制線程數量的效果,從而實現限流的策略。
該攔截器中的invoke()方法中,在執行目標方法的先後分別執行beforeAccess()和 afterAccess()方法。在beforeAccess方法中經過內部計數器concurrencyCount來對比設置的閥值concurrencyLimit,若是超過設置值,則阻塞;若沒有超過設置值,則concurrencyCount自加。在afterAccess方法中自減concurrencyCount。
6.10 AsyncExecutionAspectSupport:異步任務執行切面的一個基類。核心方法determineAsyncExecutor(),返回一個執行異步任務的線程池AsyncTaskExecutor。
6.11 AsyncExecutionInterceptor:異步任務選擇執行器。其核心方法是invoke,主要流程;(1)獲取攔截的方法。(2)根據被攔截的方法來選取執行異步任務的執行器。(3)構建任務(添加異常的處理方式)。(4)執行構建的任務並返回任務執行結果。
6.12 AsyncUncaughtExceptionHandler:異步任務執行拋出的異常catch不到時經過此接口進行處理。一個異步任務一般會返回一個java.util.concurrent.Future實例,以訪問潛在的異常,當這個異步任務不提供這個返回值時,這個句柄就負責處理此類捕獲不到的異常。
6.13 SimpleAsyncUncaughtExceptionHandler:AsyncUncaughtExceptionHandler接口的一個默認實現,用來簡單記錄這個異常。
6.14 ExposeBeanNameAdvisors:當Spring IOC容器建立自動代理bean時可使用,使得建立顧問更加便捷,將bean name綁定到當前的調用。一般在spring自動代理中使用,在代理建立時,bean的名稱就是已知的。
7、AOP/scope
7.1 ScopedObject:用於做用域對象的AOP引介接口。ScopedProxyFactoryBean建立的對象能夠轉換到這個接口,可以獲得原始的目標對象,從它的目標scopt中剝離出該對象。Spring的Bean是有scope屬性的,表示bean的生存週期。scope的值有prototype、singleton、session、request。
7.2 DefaultScopedObject:ScopedObject接口的默認實現。
7.3 ScopedProxyFactoryBean:便捷的代理工廠bean,用於做用域對象。被這個工廠bean建立的代理是單例的,線程安全,能夠會被注入到共享的對象中。
7.4 ScopedProxyUtils:建立做用域代理的一些功能性類。主要被ScopedProxyBeanDefinitionDecorator 和 ClassPathBeanDefinitionScanner使用。
8、AOP/support
8.1 AbstractExpressionPointcut:表達式切點類型的抽象超類,提供定位和表達式兩個屬性。
8.2 ExpressionPointcut:表達式切點類型,經過表達式匹配,用於支持AspectJ的表達式。
8.3 NameMatchMethodPointcut:名稱匹配切面,經過指定方法集合變量mappedNames,模糊匹配。
8.4 DynamicMethodMatcherPointcut :動態方法匹配器切點。它本質上是一個方法匹配器,但同時具備了切點的功能。
8.5 StaticMethodMatcherPointcut:靜態方法切面,抽象類。定義了一個classFilter,經過重寫getClassFilter()方法來指定切面規則。另外實現了StaticMethodMatcher接口,經過重寫matches來指定方法匹配規則。子類:NameMatchMethodPointcut(簡單字符串匹配方法簽名)和 AbstractRegexpMethodPointcut(正則表達式匹配方法簽名)。
8.6 AbstractRegexpMethodPointcut:正則表達式匹配方法簽名。
8.7 JdkRegexpMethodPointcut:JDK正則表達式切點,即便用正則表達式描述方法的攔截規則和排除規則。
8.8 ControlFlowPointcut:流程切點。
8.9 ComposablePointcut:複合切點。這種切點能夠與或邏輯,任意組合其餘的Pointcut、ClassFilter和MethodMatcher。其本質是經過ClassFilters和MethodMatchers兩個工具類進行Pointcut內部組件的組合。
8.10 AbstractPointcutAdvisor:PointcutAdvisor接口的抽象基類,其子類能夠返回指定的切點/通知,或者是一個可自由配置的切點/通知。
8.11 AbstractGenericPointcutAdvisor:通常的、通用的PointcutAdvisor。
8.12 DefaultPointcutAdvisor:默認切面顧問,比較靈活。可自由組合切面和通知。
8.13 NameMatchMethodPointcutAdvisor:方法名稱切面顧問,內部封裝了NameMatchMethodPointcut,經過設置方法名稱模糊匹配規則和通知來實現切面功能。
8.14 StaticMethodMatcherPointcutAdvisor:靜態方法匹配切面顧問,擴展了切面排序方法。
8.15 RegexpMethodPointcutAdvisor:正則表達式切面顧問,可設置多個正則表達式規則,經過內部封裝的JdkRegexpMethodPointcut解析正則表達式。
8.16 DefaultIntroductionAdvisor:默認的引介通知器,它是一種通知器,但同時兼具了類過濾器的功能,且matches總返回true。它的做用是給全部bean追加指定接口。
8.17 AbstractBeanFactoryPointcutAdvisor:基於Bean工廠的切點加強器,容許任何通知配置成指向在bean工廠中的通知bean。經過指定通知bean的名字而不是通知對象自己,在初始化時能夠下降耦合度,能夠切點真正匹配的時候再去初始化通知對象。
8.18 DefaultBeanFactoryPointcutAdvisor:AbstractBeanFactoryPointcutAdvisor抽象類的實現。基於BeanFactory的PointAdvisor,
8.19 AopUtils:該工具類是Spring很是重要的一個工具類。一個外部工具類,咱們平時若想要對AOP作一些判斷、處理,可以使用此工具類。
8.20 Pointcuts:提供了一些靜態方法,在操做切點時有用,包括matches、SetterPointcut、GetterPointcut。
8.21 ClassFilters:針對ClassFilter,還有一個工具類——ClassFilters。ClassFilters內部定義了兩個私有的靜態內部類:IntersectionClassFilter和UnionClassFilter,分別支持以與的邏輯和或的邏輯組合多個ClassFilter。此工具類同時對外提供了組合ClassFilter的API。
8.22 RootClassFilter:經過判斷目標類是不是指定類型(或其子類型),決定是否匹配。
8.23 MethodMatchers:同ClassFilters同樣,是一個工具類。
8.24 DynamicMethodMatcher:動態方法匹配器的一個抽象超類,主要用於關注運行期間的參數。
8.25 StaticMethodMatcher:靜態方法匹配的一個抽象超類,它並不關係運行時期的參數。
8.26 IntroductionInfoSupport:描述一個引介須要的基本信息接口的加強功能,其實現的子類能夠方便的從一個指定的對象所實現的全部接口提取出來,將不該該加入的接口排除掉,同時也能夠查詢全部引入的接口。
8.27 DelegatePerTargetObjectIntroductionInterceptor:引介能夠當作一種特殊的Advice,在沒有改變原先類的定義的狀況下爲其增長新的方法。這中通知是spring-aop本身定義的,因此沒有相似 @Before 這種配置能夠直接注入advice到spring容器中,故此須要本身實現 DynamicIntroductionAdvice 這個接口來進行相應邏輯處理,又因爲spring沒有對 DynamicIntroductionAdvice 的關於MethodInterceptor的適配器,故此咱們須要實現的實際上是 IntroductionInterceptor 這個接口。DelegatingIntroductionInterceptor 和DelegatePerTargetObjectIntroductionInterceptor 就是接口IntroductionInterceptor的兩個實現類。
8.28 DelegatingIntroductionInterceptor:接口IntroductionInterceptor的一個實現類,這個類就是一個委託引入攔截器,具體解釋同上。
AOP/support/annotation
8.29 AnnotationClassFilter:經過檢查目標類是否存在指定的註解,決定是否匹配
8.30 AnnotationMatchingPointcut:註解匹配切點,JDK5之後,經過註解方式聲明切點。根據類上或方法上是否存在指定的註解判斷切點的匹配性,若是沒有顯示指定註解,則匹配全部。
8.31 AnnotationMethodMatcher:註解匹配。尋找指定的Java 5的註解進行簡單的方法匹配。
9、AOP/target
9.1 AbstractBeanFactoryBasedTargetSource:此類目標源基於IoC容器實現,也就是說target目標對象能夠經過beanName從容器中獲取。此類又擴展出:(1)SimpleBeanTargetSource:簡單實現,直接調用getBean從容器獲取目標對象;(2)LazyInitTargetSource:延遲初始化目標源,子類可重寫postProcessTargetObject方法後置處理目標對象;(3)AbstractPrototypeBasedTargetSource:原型bean目標源,此抽象類可確保beanName對應的bean的scope屬性爲prototype。其子類作了簡單原型、池化原型、線程隔離原型這3種實現。
9.2 SimpleBeanTargetSource:AbstractBeanFactoryBasedTargetSource簡單實現,直接調用getBean從容器獲取目標對象。
9.3 EmptyTargetSource:靜態目標源,當不存在target目標對象,或者甚至連targetClass目標類都不存在(或未知)時,使用此類實例。
9.4 HotSwappableTargetSource:動態目標源,支持熱替換的目標源,支持spring應用運行時替換目標對象。
9.5 AbstractLazyCreationTargetSource:此類實如今調用getTarget()獲取時才建立目標對象。
9.6 LazyInitTargetSource:延遲初始化目標源,子類可重寫postProcessTargetObject方法後置處理目標對象。
9.7 SingletonTargetSource:該接口表明一個目標對象,在aop調用目標對象的時候,使用該接口返回真實的對象。Singleton表示每次調用返回同一個實例。
9.8 AbstractPrototypeBasedTargetSource:原型bean目標源,此抽象類可確保beanName對應的bean的scope屬性爲prototype。其子類作了簡單原型、池化原型、線程隔離原型這3種實現。
9.9 PrototypeTargetSource:該接口表明一個目標對象,在aop調用目標對象的時候,使用該接口返回真實的對象。Prototype表示每次調用返回每次調用返回一個新的實例。
9.10 ThreadLocalTargetSource:將獲取的bean存儲在ThreadLocal ,它在releaseTarget的操做的時候不會從ThreadLocal中釋放對應的target。
9.11 ThreadLocalTargetSourceStats:爲ThreadLocal目標源作一些統計工做。
9.12 AbstractPoolingTargetSource:這個抽象類實現了PoolConfig,表示是池類的targetSource 。
9.13 PoolingConfig:池類目標對象的配置接口。好比返回池子的最大容量,統計池子中活躍的對象數目,統計池子中空閒的對象數目。
9.14 CommonsPool2TargetSource:利用apache的ObjectPool來存儲對應的target對象,它實現了PooledObjectFactory,這個池中的對象仍是從beanFactory中獲取。
AOP/target/dynamic
9.15 Refreshable:會被動態目標對象實現的接口,支持經過從新載入,輪詢進行刷新。
9.16 AbstractRefreshableTargetSource:可刷新的目標源。此類實現可根據配置的刷新延遲時間,在每次獲取目標對象時自動刷新目標對象。
9.17 BeanFactoryRefreshableTargetSource:可刷新的目標源。其target bean是從bean工廠中獲取的,每次刷新週期到來時都會自動進行刷新。其子類也能夠重寫方法requiresRefresh(),把一些沒必要要的刷新給取消掉。
3、JDK動態代理
Spring默認採起的動態代理機制實現AOP, 簡單來講就是在程序運行期間動態的將某段代碼切入到指定方法指定位置進行運行的編程方式。動態代理技術包括Java動態代理和CGLIB動態代理,前者基於接口實現,後者基於類實現。Spring默認採起的Java動態代理機制實現AOP。在介紹Spring AOP原理以前先介紹Java動態代理。
(一)什麼是代理
編程中有個思想,不要隨意的去修改別人已經寫好的代碼或者方法。可是若是我想在原有實現的基礎上增長額外的功能呢,即對目標對象的功能進行拓展。好比在執行某個方法的時候記錄下日誌,這個時候就可使用代理。
代理是一種常見的設計模式,其目的就是爲目標對象提供一個代理對象以控制對目標對象的訪問,即經過代理對象訪問目標對象。其中代理對象是目標對象的拓展,而且會使用到目標對象。
代理模式又分爲靜態代理和動態代理。靜態代理簡單來講就是代理類和目標類(委託類)實現同一個接口,而後代理類中引入對目標類對象的引用。目的:這樣能夠實現一些其餘功能,可是不會讓目標類變得膨脹。缺點:這樣必須爲目標對象建立一個實現了相同接口的代理對象,而且代理對象中的方法也要和目標對象保持一致。一旦目標對象改動了,代理對象也要變動相應的代碼。這樣就出現了大量的重複代碼,增長了代碼的維護複雜度。並且這種方法代理對象只能服務於一種類型的目標對象,若是要服務多個類型的對象,則須要爲每一種對象都進行代理。舉例:好比我想在調用具體實現類先後打印日誌等信息,在不修改已有代碼的狀況下,咱們只須要增長一個代理類,在代理類中增長打印日誌的功能,而後去調用目標類,這樣就能夠避免修改目標類。在建立代理對象時,經過構造器塞入一個目標對象,而後在代理對象的方法內部調用目標對象同名方法,並在調用先後打印日誌。也就是說,代理對象=目標對象+加強代碼,有了代理對象以後,就不用原對象了。可是若是想讓多個目標類都添加打印日誌功能,那麼就須要增長多個代理類,代理類中各個方法都要增長打印日誌功能,這就不堪負重了。
動態代理:上面咱們知道靜態代理每一個代理類只能爲一個接口服務,這樣程序中就會出現不少代理類,動態代理能夠經過一個代理類完成所有的代理功能。這個代理類是在運行時候動態生成的,是經過反射機制動態建立(反射機制是指在運行狀態中,對於任意一個類,都能知道這個類的全部屬性和方法,對於任意一個對象,都可以調用它的任意屬性和方法。)這樣不須要爲每個接口寫一個代理類,避免一個類對應一個代理的問題,大大提升了系統的靈活性,減小重複,下降了代碼維護的複雜性和成本。Java動態代理機制以巧妙的方式實踐了代理模式的設計理念。
Java動態代理:Java的動態代理是基於接口的,代理類和目標類實現相同的接口,這樣他們行爲保持了一致性,在訪問者看來二者沒有絲毫的區別。經過代理類這中間一層,能有效的對委託類的對象的直接訪問,能夠很好的隱藏和保護委託對象,同時爲實施不一樣的策略預留空間。
(二)Java的動態代理類
Java動態代理機制中有兩個重要的接口和類:接口InvocationHandler()和類Proxy(),位於java.lang.reflect包中,這是實現動態代理的核心。
(1)接口InvocationHandler:動態代理類的調用處理程序
InvocationHandler接口是proxy代理實例的調用處理程序實現的一個接口,該接口中僅定義了一個方法:
public Object invoke(Object proxy, Method method, Object[] args)
其中:第一個參數proxy表示執行這個方法的代理對象,method表示目標對象實際須要執行的方法,args表示目標對象實際要執行的方法所須要的參數。
每個proxy代理實例都要有一個關聯的調用處理程序,該調用處理程序都必須實現InvocationHandler接口。因此在實際編程中,須要先定義一個實現了InvocationHandler接口的調用處理器對象,而後將它做爲建立代理類實例的參數(見Proxy類的newProxyInstance()方法)。
(2)Proxy:動態代理類
Proxy類就是用來建立一個代理對象的類,最經常使用的方法是static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)。這個方法的做用就是建立一個代理對象,其中三個參數爲:
一、ClassLoader loader:指定當前目標對象使用類加載器,對於不一樣來源(系統庫或網絡等)的類須要不一樣的類加載器來加載,這是Java安全模型的一部分。
二、Class[] interfaces:一個interface對象數組,目標對象實現的接口的類型。表示咱們要給代理對象提供什麼樣的接口。若是咱們提供了這樣一個接口對象數組,那麼也就是聲明瞭代理類實現了這些接口,代理類就能夠調用接口中聲明的全部方法。
三、InvocationHandler h:一個InvocationHandler調用處理程序對象,它必須是實現了InvocationHandler接口的對象,做用就是定義代理對象中須要執行的具體操做。當執行目標對象的方法時,會關聯到一個InvocationHandler對象上,從而觸發調用處理程序的方法,會把當前執行目標對象的方法做爲參數傳入,並最終調用h中的invoke()方法。
其實動態代理類能夠看作是這樣一種類:它是在運行時生成的類,在生成它時你必須提供一組接口給它,而後該類就宣稱它實現了這些接口。你固然能夠把該類的實例當作這裏接口中的任何一個來用。固然,這個動態代理類其實就是一個代理,它不會替你作實質性的工做,在生成它的實例時你必須提供一個handler,由它接管實際的工做。在實際使用代理類的時候,咱們必須實現InvocationHandler接口。這樣目標對象、須要控制的接口和控制方式均可以動態改變,從而實現靈活的動態代理關係。
(三)動態代理的步驟
一、建立目標類(委託類)的接口
這裏定義了兩個接口,interface IBusiness1 和interface IBusiness2,各包含一個方法。
interface IBusiness1:
1 package com.dynamicproxy; 2 3 public interface IBusiness1 { 4 public void doSomeThing1() ; 5 }
interface IBusiness2:
1 package com.dynamicproxy; 2 3 public interface IBusiness2 { 4 public void doSomeThing2() ; 5 }
二、建立目標類(委託類)
建立一個目標類Business,實現這兩個接口。
1 package com.dynamicproxy; 2 3 public class Business implements IBusiness1, IBusiness2 { 4 @Override 5 public void doSomeThing1() { System.out.println("執行業務邏輯1"); } 6 7 @Override 8 public void doSomeThing2() { 9 System.out.println("執行業務邏輯2"); 10 } 11 }
三、定義一個代理類的調用處理程序。該程序必須實現接口InvocationHandler,且必須實現接口的invoke方法。
InvocationHandler接口是proxy代理實例的調用處理程序實現的一個接口,每個proxy代理實例都有一個關聯的調用處理程序;在代理實例調用方法時,方法調用被轉發到調用處理程序的invoke方法。
1 package com.dynamicproxy; 2 3 import java.lang.reflect.Method; 4 import java.lang.reflect.InvocationHandler; 5 6 public class LogInvocationHandler implements InvocationHandler{ 7 //目標對象 8 private Object target; 9 10 //構造函數,給目標對象賦值 11 LogInvocationHandler(Object target) { 12 this.target = target; 13 } 14 15 @Override 16 /** 17 * proxy:代理類 18 * method:被代理的方法 19 * args:該方法的參數數組 20 */ 21 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 22 //在真實的對象執行以前添加本身的操做 23 System.out.println("日誌: 方法" + method.getName() + "即將執行"); 24 //執行原有邏輯 25 Object rev = method.invoke(target, args); 26 //在真實的對象執行以後添加本身的操做 27 System.out.println("日誌: 方法" + method.getName() + "執行完畢"); 28 29 return rev; 30 } 31 }
四、經過Proxy的靜態方法newProxyInstance()建立一個代理對象。
Proxy類就是用來建立一個代理對象的類,它提供了不少方法,可是咱們最經常使用的是newProxyInstance方法。這個方法的做用就是建立一個代理類對象。該方法有三個參數,三個參數具體解釋見上述。
1 package com.dynamicproxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Proxy; 5 6 public class Test { 7 public static void main(String[] args) { 8 //要代理的目標對象 9 Business myBusiness = new Business(); 10 //代理類要實現的接口列表 11 Class[] proxyInterface = myBusiness.getClass().getInterfaces(); 12 13 //代理對象的調用處理程序。咱們將要代理的目標對象傳入代理對象的調用處理的構造函數中,代理對象的調用處理程序最終會調用目標對象的方法 14 LogInvocationHandler handler = new LogInvocationHandler(myBusiness); 15 16 /** 17 * 經過Proxy類的newProxyInstance方法建立代理對象 18 * 第一個參數:handler.getClass().getClassLoader(),使用handler對象的classloader對象來加載咱們的代理對象 19 * 第二個參數:proxyInterface,這裏爲代理類提供的接口是目標對象實現的接口,這樣代理對象就能像目標對象同樣調用接口中的全部方法 20 * 第三個參數:handler,咱們將代理對象關聯到上面的InvocationHandler對象上 21 */ 22 IBusiness1 proxyBusiness = (IBusiness1) Proxy.newProxyInstance(handler.getClass().getClassLoader(), proxyInterface, handler); 23 24 //使用代理類的實例來調用方法。 25 proxyBusiness.doSomeThing1(); 26 ((IBusiness2) proxyBusiness).doSomeThing2(); 27 } 28 }
五、經過代理對象調用委託類對象的方法。
其實Proxy類只是一個鏈接橋,把代理(InvocationHandler)與被代理類關聯起來,真正處理事情的是InvocaHandler。InvocationHandler接口中的invoke方法在代理類中是動態實現的,當咱們經過動態代理調用一個方法的時候,這個方法的調用會被轉發到到調用處理程序的invoke方法中。
1 //使用代理類的實例來調用方法。 2 proxyBusiness.doSomeThing1(); 3 ((IBusiness2) proxyBusiness).doSomeThing2();
運行結果:
動態代理的優點就是能夠很方便的對目標類的函數進行統一的處理,而不用修改每一個目標類的方法。全部被代理執行的方法在調用執行的時候,其方法只是做爲參數傳入InvocationHandler中的invoke方法,實際是在invoke方法中處理的,這樣經過在invoke方法中咱們能夠對全部被代理的方法進行相同的加強操做。
4、Spring AOP的實現原理
下面Spring AOP實現流程圖:
(一)標籤的解析
首先咱們來看下AOP經常使用的兩種實現方式,一種是採用聲明的方式來實現(基於XML),一種是採用註解的方式來實現(基於AspectJ)。下面舉例說明:
方式一:xml方式配置
第一步:建立被增強類
1 package cn.ytk.dao; 2 import org.springframework.stereotype.Repository; 3 4 @Repository 5 public class UserDao { 6 public void sys() { 7 System.out.println("userDao....."); 8 } 9 }
第二步:建立加強類
1 package cn.ytk.strong; 2 3 import org.aspectj.lang.ProceedingJoinPoint; 4 5 public class Project { 6 public void before1() { 7 System.out.println("前置通知。。。。。。。。。"); 8 } 9 //環繞通知 10 public void around(ProceedingJoinPoint point) throws Throwable { 11 System.out.println("環繞通知前。。。。。"); 12 point.proceed(); 13 System.out.println("環繞通知後。。。。。。"); 14 } 15 16 public void after1() { 17 System.out.println("後置通知。。。。。。。。。"); 18 } 19 }
第三步:配置切點和切面
1 <!-- spring bean的配置 --> 2 <bean id="userDao" class="cn.ytk.dao.UserDao"></bean> 3 <bean id="userService" class="cn.ytk.service.UserService"> 4 <property name="userDao" ref="userDao"></property> 5 </bean> 6 <bean id="project" class="cn.ytk.strong.Project"></bean> 7 8 <aop:config> 9 <aop:pointcut expression="execution(* cn.ytk.dao.UserDao.*(..))" id="pointcut1"/> 10 <aop:aspect ref="project"> 11 <aop:before method="before1" pointcut-ref="pointcut1"/> 12 <aop:after-returning method="after1" pointcut-ref="pointcut1"/> 13 <aop:around method="around" pointcut-ref="pointcut1"/> 14 </aop:aspect> 15 </aop:config>
方式二:經過Spring AOP註解實現
第一步:配置spring文件,開啓aop註解
1 <!-- 開啓aop的註解 --> 2 <aop:aspectj-autoproxy/> 3 <context:component-scan base-package="cn.ytk.*"></context:component-scan>
第二步:編寫加強類
1 package cn.ytk.strong; 2 3 import org.aspectj.lang.ProceedingJoinPoint; 4 import org.aspectj.lang.annotation.AfterReturning; 5 import org.aspectj.lang.annotation.Aspect; 6 import org.aspectj.lang.annotation.Before; 7 import org.aspectj.lang.annotation.Pointcut; 8 import org.springframework.stereotype.Component; 9 10 @Component 11 @Aspect 12 public class Project2 { 13 //方式1: 14 @Before(value="execution(* cn.ytk.dao.UserDao.*(..))") 15 public void before() { 16 System.out.println("前置通知。。。。。。"); 17 } 18 19 //方式2:先編寫切點在將切點加到增強上。 20 @Pointcut("execution(* cn.ytk.dao.*.*(..))") 21 public void after() {} 22 23 @AfterReturning("after()") 24 public void after1() { 25 System.out.println("....後置通知...."); 26 } 27 }
從示例中看出,XML方式中使用AOP技術的須要作如下幾步:
1)開啓AOP註解,<aop:aspectj-autoproxy/>
2)定義切面類,使用@Aspect註解
3)在切面類上加設註解@Component
4)在切面類中定義切點方法,使用@PointCut註解
5)在切面類中定義通知方法,使用@Before、@After、@Around等註解
6)在通知方法的註解中使用切點方法
下面結合Spring AOP的源碼對AOP的實現原理一步步進行分析:
聲明瞭自定義的註解,必定會在程序的某個地方註冊對應的解析器。<aop:aspectj-autoproxy/>註解使用AspectJAutoProxyBeanDefinitionParser解析器進行解析。這個對應關係在AopNamespaceHandler(package org.springframework.aop.config)類中指定。
1 public void init() { 2 // In 2.0 XSD as well as in 2.1 XSD. 3 registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); 4 registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); 5 registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); 6 7 // Only in 2.0 XSD: moved to context namespace as of 2.1 8 registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); 9 }
接着來看下AspectJAutoProxyBeanDefinitionParser(package org.springframework.aop.config)解析器的代碼。它是一個實現了BeanDefinitionParser接口的類,專門用於解析切面自動代理的Bean定義的解析工做,重點在其parse方法。
1 @Override 2 @Nullable 3 public BeanDefinition parse(Element element, ParserContext parserContext) { 4 //註冊AnnotationAwareAspectJAutoProxyCreator 5 AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); 6 //對註解中子類的處理 7 extendBeanDefinition(element, parserContext); 8 return null; 9 }
其中調用了AopNamespaceUtils類(處理Spring AOP命名空間的工具類,package org.springframework.aop.config)的registerAspectJAnnotationAutoProxyCreatorIfNecessary函數。咱們進入此函數看一下代碼邏輯:
1 public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary( 2 ParserContext parserContext, Element sourceElement) { 3 //註冊或者升級AutoProxyCreator定義beanName爲 4 // org.Springframework.aop.config.internalAutoProxyCreator的BeanDefinition 5 BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary( 6 parserContext.getRegistry(), parserContext.extractSource(sourceElement)); 7 //對於proxy-target-class以及expose-proxy屬性的處理 8 useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); 9 //註冊組件並通知,便於監聽器進一步處理,其中BeanDefinition的className 10 // 爲AnnotationAwareAspectJAutoProxyCreator 11 registerComponentIfNecessary(beanDefinition, parserContext); 12 }
上述代碼一共三行代碼,每行代碼完成一件事情,都是一個完整的邏輯。
第一行代碼:BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary( parserContext.getRegistry(), parserContext.extractSource(sourceElement));
註冊或者升級AnnotatonAwareAspectJAutoProxyCreator。
咱們進入AopConfigUtils類(package org.springframework.aop.config)的registerAspectJAnnotationAutoProxyCreatorIfNecessary函數看看:
1 @Nullable 2 public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary( 3 BeanDefinitionRegistry registry, @Nullable Object source) { 4 5 return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); 6 }
上面這個函數又實際調用了本類中的registerOrEscalateApcAsRequired函數,咱們繼續查看該函數的實現邏輯:
1 @Nullable 2 private static BeanDefinition registerOrEscalateApcAsRequired( 3 Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) { 4 5 Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); 6 7 //若是已經存在了自動代理建立器且存在的自動代理建立器與如今的不一致, 8 // 那麼須要根據優先級判斷到底使用哪一個 9 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { 10 BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); 11 if (!cls.getName().equals(apcDefinition.getBeanClassName())) { 12 int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); 13 int requiredPriority = findPriorityForClass(cls); 14 if (currentPriority < requiredPriority) { 15 //改變bean最重要的就是改變bean所對應的className屬性 16 apcDefinition.setBeanClassName(cls.getName()); 17 } 18 } 19 //若是已經存在自動代理建立器且與將要建立的一致,那麼無需再次建立 20 return null; 21 } 22 23 RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); 24 beanDefinition.setSource(source); 25 beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); 26 beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); 27 registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); 28 return beanDefinition; 29 }
對於Aop的實現,基本都是靠AnnotatonAwareAspectJAutoProxyCreator去完成的,它能夠根據@Point註解定義的切點來自動代理相匹配的bean。可是爲了配置簡便,Spring使用了自定義的配置幫助咱們自動註冊AnnotatonAwareAspectJAutoProxyCreator。其註冊過程就是在上述函數中實現的。上述代碼實現了自動註冊AnnotatonAwareAspectJAutoProxyCreator類的功能,同時存在優先級問題,若是已經存在了自動代理建立器,並且存在的與如今的不一致,那麼須要根據優先級判斷到底使用哪一個。
第二行代碼:useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
處理proxy-target-class和expose-proxy屬性,進入該函數:
1 private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) { 2 if (sourceElement != null) { 3 //對應proxy-target-class屬性的處理 4 boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE)); 5 if (proxyTargetClass) { 6 AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); 7 } 8 //對應expose-proxy屬性的處理 9 boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE)); 10 if (exposeProxy) { 11 AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); 12 } 13 } 14 }
proxy-target-class和expose-proxy屬性解釋:
(1)proxy-target-class屬性
Spring AOP使用JDK動態代理或者CGLIB來爲目標對象建立代理。若是被代理的目標對象至少實現了一個接口,則使用JDK動態代理,全部該目標類型實現的接口都將被代理。若是該目標對象沒有實現任何接口,則建立一個CGLIB代理。也能夠強制使用CGLIB代理,強制使用CGLIB代理須要將<aop:config>的proxy-target-class屬性設置爲true:<aop:config proxy-target-class=」true」>…</aop:config>
當須要使用CGLIB代理和@AspectJ自動代理支持,能夠按照下面的方式設置<aop:aspectj-autoproxy>的proxy-target-class屬性:<aop:aspectj-autoproxy proxy-target-class=」true」>。
(2)expose-proxy屬性
Spring AOP沒法攔截內部方法調用,好比一個接口裏面有兩個方法:doSomething1()和doSomething2()。而後在方法1中調用了方法2:this.doSomething2()。此處this指向目標對象,所以調用this.doSomething2()將不會執行doSomething2的加強。(也就是切面只會對doSomething1方法進行加強,可是不會對doSomething2進行加強)。
解決方法:this. doSomething2 ()修改成 ((AService) AopContext.currentProxy()).doSomething2 ()。同時修改Spring AOP的配置:<aop:aspectj-autoproxy expose-proxy="true" />
第三行代碼:registerComponentIfNecessary(beanDefinition, parserContext);
註冊組件並通知,便於監聽器進一步處理。
(二)獲取加強方法或者加強器
上面經過自定義配置完成了對AnnotatonAwareAspectJAutoProxyCreator(package org.springframework.aop.aspectj.annotation中)的自動註冊。
AnnotatonAwareAspectJAutoProxyCreator類:SpringBoot框架中默認支持的方式。spring aop 開啓註解方式以後,該類會掃描全部@Aspect()註釋的類,生成對應的advisor。
AnnotationAwareAspectJAutoProxyCreator的繼承關係以下:
AnnotationAwareAspectJAutoProxyCreator
--AspectJAwareAdvisorAutoProxyCreator
--AbstractAdvisorAutoProxyCreator
--AbstractAutoProxyCreator
-- ProxyProcessorSupport;
SmartInstantiationAwareBeanPostProcessor;
BeanFactoryAware;
其中
ProxyProcessorSupport
--ProxyConfig;
Ordered;
BeanClassLoaderAware;
AopInfrastructureBean;
SmartInstantiationAwareBeanPostProcessor
--InstantiationAwareBeanPostProcessor
--BeanPostProcessor
BeanFactoryAware
--Aware
AnnotatonAwareAspectJAutoProxyCreator間接實現了BeanPostProcessor接口,因此當Spring加載這個Bean的時候會在實例化以前調用postProcessAfterInitialization這個方法。一直往父類尋找,在其父類AbstractAutoProxyCreator(package org.springframework.aop.framework.autoproxy)實現了該方法。
1 @Override 2 public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { 3 if (bean != null) { 4 //根據給定的bean的class和name構建出key,格式:beanClassName_beanName 5 Object cacheKey = getCacheKey(bean.getClass(), beanName); 6 if (this.earlyProxyReferences.remove(cacheKey) != bean) { 7 //一個很是核心的方法:wrapIfNecessary(),若是它適合被代理,則須要封裝指定的bean。 8 return wrapIfNecessary(bean, beanName, cacheKey); 9 } 10 } 11 return bean; 12 }
其有一個很是核心的方法:wrapIfNecessary()。繼續進入該類中的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 //若是已經處理過 10 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { 11 return bean; 12 } 13 //這個bean無需加強 14 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { 15 return bean; 16 } 17 //判斷給定的bean是不是一個基礎設施類,基礎設施類不該代理,或者配置了指定bean不須要代理。 18 //所謂InfrastructureClass就是指Advice/PointCut/Advisor等接口的實現類。 19 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { 20 this.advisedBeans.put(cacheKey, Boolean.FALSE); 21 return bean; 22 } 23 24 // 若是存在加強方法則建立代理 25 //獲取這個bean的advice 26 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); 27 //若是獲取到了加強則須要針對加強建立代理 28 if (specificInterceptors != DO_NOT_PROXY) { 29 this.advisedBeans.put(cacheKey, Boolean.TRUE); 30 //建立代理 31 Object proxy = createProxy( 32 bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); 33 this.proxyTypes.put(cacheKey, proxy.getClass()); 34 return proxy; 35 } 36 37 this.advisedBeans.put(cacheKey, Boolean.FALSE); 38 return bean; 39 }
從上述代碼中咱們看到了代理建立的雛形。建立代理主要包含了兩個步驟:一、獲取加強方法或者加強器。二、根據獲取的加強進行代理。
下面咱們先來看下獲取加強方法或者加強器:
AbstractAutoProxyCreator類的wrapIfNecessary方法中調用了getAdvicesAndAdvisorsForBean,AbstractAutoProxyCreator類只對該方法進行定義,真正實如今其子類AbstractAdvisorAutoProxyCreator(package org.springframework.aop.framework.autoproxy)中實現。
1 protected Object[] getAdvicesAndAdvisorsForBean( 2 Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { 3 4 List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); 5 if (advisors.isEmpty()) { 6 return DO_NOT_PROXY; 7 } 8 return advisors.toArray(); 9 }
上面方法實現又調用了該類中的findEligibleAdvisors方法,進入其代碼:
1 protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { 2 List<Advisor> candidateAdvisors = findCandidateAdvisors(); 3 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); 4 extendAdvisors(eligibleAdvisors); 5 if (!eligibleAdvisors.isEmpty()) { 6 eligibleAdvisors = sortAdvisors(eligibleAdvisors); 7 } 8 return eligibleAdvisors; 9 }
裏面有兩個函數findCandidateAdvisors和findAdvisorsThatCanApply。這兩個方法就是來獲取全部的加強以及尋找加強中適用於bean的加強並應用。
(1) findCandidateAdvisors方法(獲取全部的加強)
咱們首先進入findCandidateAdvisors看下:
1 protected List<Advisor> findCandidateAdvisors() { 2 Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available"); 3 return this.advisorRetrievalHelper.findAdvisorBeans(); 4 }
方法中調用了BeanFactoryAdvisorRetrievalHelper類(package org.springframework.aop.framework.autoproxy中)的findAdvisorBeans方法(AbstractAdvisorAutoProxyCreator類中聲明瞭advisorRetrievalHelper是BeanFactoryAdvisorRetrievalHelper類型。private BeanFactoryAdvisorRetrievalHelper advisorRetrievalHelper;)。
BeanFactoryAdvisorRetrievalHelper這個類是一個Spring AOP內部工具類,用來從bean容器中獲取全部Spring的Advisor bean(這裏的 Spring Advisor bean指的是實現了接口org.springframework.aop.Advisor的bean)。是真正去容器中找出全部的Advisor的類。該工具內部使用了緩存機制,雖然公開的查找方法可能會被調用屢次,但並非每次都會真正查找,而是會利用緩存。
1 public List<Advisor> findAdvisorBeans() { 2 //cachedAdvisorBeanNames是advisor名稱的緩存 3 String[] advisorNames = this.cachedAdvisorBeanNames; 4 //若是cachedAdvisorBeanNames爲空,則到容器中查找,並設置緩存,後續直接使用緩存便可 5 if (advisorNames == null) { 6 // Do not initialize FactoryBeans here: We need to leave all regular beans 7 // uninitialized to let the auto-proxy creator apply to them! 8 //從容器中查找Advisor類型的bean的名稱 9 advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( 10 this.beanFactory, Advisor.class, true, false); 11 this.cachedAdvisorBeanNames = advisorNames; 12 } 13 if (advisorNames.length == 0) { 14 return new ArrayList<>(); 15 } 16 17 List<Advisor> advisors = new ArrayList<>(); 18 //遍歷advisorNames 19 for (String name : advisorNames) { 20 if (isEligibleBean(name)) { 21 //忽略鄭州建立中的advisor bean 22 if (this.beanFactory.isCurrentlyInCreation(name)) { 23 if (logger.isTraceEnabled()) { 24 logger.trace("Skipping currently created advisor '" + name + "'"); 25 } 26 } 27 else { 28 try { 29 //調用getBean方法從容器中獲取名稱爲name的bean,並將bean添加到advisors中 30 advisors.add(this.beanFactory.getBean(name, Advisor.class)); 31 } 32 catch (BeanCreationException ex) { 33 Throwable rootCause = ex.getMostSpecificCause(); 34 if (rootCause instanceof BeanCurrentlyInCreationException) { 35 BeanCreationException bce = (BeanCreationException) rootCause; 36 String bceBeanName = bce.getBeanName(); 37 if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) { 38 if (logger.isTraceEnabled()) { 39 logger.trace("Skipping advisor '" + name + 40 "' with dependency on currently created bean: " + ex.getMessage()); 41 } 42 // Ignore: indicates a reference back to the bean we're trying to advise. 43 // We want to find advisors other than the currently created bean itself. 44 continue; 45 } 46 } 47 throw ex; 48 } 49 } 50 } 51 } 52 return advisors; 53 }
(2)findAdvisorsThatCanApply方法(尋找加強中適用於bean的加強並應用)
咱們首先進入findAdvisorsThatCanApply看下:
1 protected List<Advisor> findAdvisorsThatCanApply( 2 List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { 3 4 ProxyCreationContext.setCurrentProxiedBeanName(beanName); 5 try { 6 return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); 7 } 8 finally { 9 ProxyCreationContext.setCurrentProxiedBeanName(null); 10 } 11 }
方法調用了AopUtils類(package org.springframework.aop.support中)的findAdvisorsThatCanApply方法。
1 public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { 2 if (candidateAdvisors.isEmpty()) { 3 return candidateAdvisors; 4 } 5 List<Advisor> eligibleAdvisors = new ArrayList<>(); 6 for (Advisor candidate : candidateAdvisors) { 7 //刷選IntroductionAdvisor引介類型的通知器 8 if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { 9 eligibleAdvisors.add(candidate); 10 } 11 } 12 boolean hasIntroductions = !eligibleAdvisors.isEmpty(); 13 for (Advisor candidate : candidateAdvisors) { 14 if (candidate instanceof IntroductionAdvisor) { 15 //引介加強已經處理 16 continue; 17 } 18 //刷選普通類型的通知器 19 if (canApply(candidate, clazz, hasIntroductions)) { 20 eligibleAdvisors.add(candidate); 21 } 22 } 23 return eligibleAdvisors; 24 }
該函數調用了該類中的canApply方法,該方法實現了重載,其代碼以下:
1 public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { 2 Assert.notNull(pc, "Pointcut must not be null"); 3 //使用 ClassFilter 匹配 class 4 if (!pc.getClassFilter().matches(targetClass)) { 5 return false; 6 } 7 8 MethodMatcher methodMatcher = pc.getMethodMatcher(); 9 if (methodMatcher == MethodMatcher.TRUE) { 10 // No need to iterate the methods if we're matching any method anyway... 11 return true; 12 } 13 14 IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; 15 if (methodMatcher instanceof IntroductionAwareMethodMatcher) { 16 introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; 17 } 18 19 20 /* 21 * 查找當前類及其父類(以及父類的父類等等)所實現的接口,因爲接口中的方法是 public, 22 * 因此當前類能夠繼承其父類,和父類的父類中全部的接口方法 23 */ 24 Set<Class<?>> classes = new LinkedHashSet<>(); 25 if (!Proxy.isProxyClass(targetClass)) { 26 classes.add(ClassUtils.getUserClass(targetClass)); 27 } 28 classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); 29 30 for (Class<?> clazz : classes) { 31 // 獲取當前類的方法列表,包括從父類中繼承的方法 32 Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz); 33 for (Method method : methods) { 34 // 使用 methodMatcher 匹配方法,匹配成功便可當即返回 35 if (introductionAwareMethodMatcher != null ? 36 introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) : 37 methodMatcher.matches(method, targetClass)) { 38 return true; 39 } 40 } 41 } 42 43 return false; 44 }
1 public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) { 2 if (advisor instanceof IntroductionAdvisor) { 3 /* 4 * 從通知器中獲取類型過濾器 ClassFilter,並調用 matchers 方法進行匹配。 5 * ClassFilter 接口的實現類 AspectJExpressionPointcut 爲例,該類的 6 * 匹配工做由 AspectJ 表達式解析器負責,具體匹配細節這個就無法分析了,我 7 * AspectJ 表達式的工做流程不是很熟 8 */ 9 return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); 10 } 11 else if (advisor instanceof PointcutAdvisor) { 12 PointcutAdvisor pca = (PointcutAdvisor) advisor; 13 // 對於普通類型的通知器,這裏繼續調用重載方法進行篩選 14 return canApply(pca.getPointcut(), targetClass, hasIntroductions); 15 } 16 else { 17 // It doesn't have a pointcut so we assume it applies. 18 return true; 19 } 20 }
以上是通知器篩選的過程,篩選的工做主要由 ClassFilter 和 MethodMatcher 完成。
因此獲取加強器的主要流程:(1)獲取全部bean名稱;(2)遍歷全部bean名稱找出其中標記Aspect的bean;(3)解析並構造獲取bean的全部加強器;(4)將解析到的加強器添加到緩存中;(5)過濾匹配出當前bean的加強器。
(三)根據獲取的加強建立代理
咱們再回到AbstractAutoProxyCreator類的wrapIfNecessary方法。從這個方法代碼中咱們看到了代理建立的雛形。建立代理主要包含了兩個步驟:一、獲取加強方法或者加強器。二、根據獲取的加強進行代理。上面咱們介紹了獲取加強方法或者加強器,下面咱們看下根據獲取的加強進行代理。
wrapIfNecessary函數中建立代理用了調用了Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
咱們進入AbstractAutoProxyCreator類中的createProxy函數:
1 protected Object createProxy(Class<?> beanClass, @Nullable String beanName, 2 @Nullable Object[] specificInterceptors, TargetSource targetSource) { 3 4 if (this.beanFactory instanceof ConfigurableListableBeanFactory) { 5 AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); 6 } 7 8 ProxyFactory proxyFactory = new ProxyFactory(); 9 //步驟1:獲取當前類的屬性。 10 proxyFactory.copyFrom(this); 11 12 //步驟2:添加代理接口。 13 if (!proxyFactory.isProxyTargetClass()) { 14 if (shouldProxyTargetClass(beanClass, beanName)) { 15 proxyFactory.setProxyTargetClass(true); 16 } 17 else { 18 evaluateProxyInterfaces(beanClass, proxyFactory); 19 } 20 } 21 22 //步驟3:攔截器封裝轉化爲加強器 23 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); 24 //步驟4:將Advisor加入到ProxyFactory中。 25 proxyFactory.addAdvisors(advisors); 26 //步驟5:設置要代理的類。 27 proxyFactory.setTargetSource(targetSource); 28 //步驟6:爲子類提供了定製函數customizeProxyFactory 29 customizeProxyFactory(proxyFactory); 30 31 //步驟7:設置是否須要凍結代理對象。用來控制代理工廠被配置後,是否還容許修改通知。缺省值爲false 32 proxyFactory.setFrozen(this.freezeProxy); 33 if (advisorsPreFiltered()) { 34 proxyFactory.setPreFiltered(true); 35 } 36 37 //步驟8:進行代理操做。 38 return proxyFactory.getProxy(getProxyClassLoader()); 39 }
此函數主要是對ProxyFactory的初始化操做,進而對真正的代理建立作準備。這些初始化操做包括:
步驟1:獲取當前類的屬性。
步驟2:添加代理接口。
步驟3:攔截器封裝轉化爲加強器
步驟4:將Advisor加入到ProxyFactory中。
步驟5:設置要代理的類。
步驟6:在Spring中還爲子類提供了定製函數customizeProxyFactory,子類能夠在此函數中對ProxyFactory進一步封裝。
步驟7:設置是否須要凍結代理對象
步驟8:進行代理操做。
下面咱們重點先來看下步驟三、四、8.
步驟3 :Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
步驟4:proxyFactory.addAdvisors(advisors);
步驟8: return proxyFactory.getProxy(getProxyClassLoader())
(1)步驟3:將攔截器封裝轉化爲加強器。
首先要將攔截器封裝轉化爲加強器,實現函數爲buildAdvisors方法,在該類AbstractAutoProxyCreator中,代碼以下:
1 protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) { 2 // 解析註冊全部的InterceptorNames 3 Advisor[] commonInterceptors = resolveInterceptorNames(); 4 5 List<Object> allInterceptors = new ArrayList<>(); 6 if (specificInterceptors != null) { 7 //加入攔截器 8 allInterceptors.addAll(Arrays.asList(specificInterceptors)); 9 if (commonInterceptors.length > 0) { 10 if (this.applyCommonInterceptorsFirst) { 11 allInterceptors.addAll(0, Arrays.asList(commonInterceptors)); 12 } 13 else { 14 allInterceptors.addAll(Arrays.asList(commonInterceptors)); 15 } 16 } 17 } 18 if (logger.isTraceEnabled()) { 19 int nrOfCommonInterceptors = commonInterceptors.length; 20 int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0); 21 logger.trace("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors + 22 " common interceptors and " + nrOfSpecificInterceptors + " specific interceptors"); 23 } 24 25 Advisor[] advisors = new Advisor[allInterceptors.size()]; 26 for (int i = 0; i < allInterceptors.size(); i++) { 27 //將攔截器進行封裝轉化成Advisor 28 advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i)); 29 } 30 return advisors; 31 }
上述方法調用了接口advisorAdapterRegistry的wrap方法,DefaultAdvisorAdapterRegistry類(package org.springframework.aop.framework.adapter)是接口advisorAdapterRegistry的默認實現,用來完成各類通知的適配和註冊過程。將Advice包裝成Advisor(DefaultPointCutAdvisor),藉助AdvisorAdapter,將Advisor包裝成MethodInterceptor。咱們進入此類中的wrap方法:
1 @Override 2 public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException { 3 //若是要封裝的對象自己就是Advisor類型的,那麼無需再作過多的處理 4 if (adviceObject instanceof Advisor) { 5 return (Advisor) adviceObject; 6 } 7 //由於此封裝方法只對Advisor與Advice兩種類型的數據有效,若是不是將不能封裝 8 if (!(adviceObject instanceof Advice)) { 9 throw new UnknownAdviceTypeException(adviceObject); 10 } 11 Advice advice = (Advice) adviceObject; 12 if (advice instanceof MethodInterceptor) { 13 //若是是MethodInterceptor類型,則使用DefaultPointcutAdvisor封裝 14 return new DefaultPointcutAdvisor(advice); 15 } 16 //若是存在Advisor的適配器,那麼也一樣須要進行封裝 17 for (AdvisorAdapter adapter : this.adapters) { 18 // Check that it is supported. 19 if (adapter.supportsAdvice(advice)) { 20 return new DefaultPointcutAdvisor(advice); 21 } 22 } 23 throw new UnknownAdviceTypeException(advice); 24 }
(2)步驟4:將Advisor加入到ProxyFactory中。
將攔截器封裝轉化爲加強器後,再經過ProxyFactory提供的addAdvisor方法將加強器置入建立工廠中。AbstractAutoProxyCreator.createProxy函數中直接調用了proxyFactory.addAdvisor (advisors)。proxyFactory繼承自ProxyCreatorSupport,ProxyCreatorSupport繼承自AdvisedSupport。addAdvisor這個方法實際在AdvisedSupport類(package org.springframework.aop.framework)中給出。
1 public void addAdvisor(int pos, Advisor advisor) throws AopConfigException { 2 if (advisor instanceof IntroductionAdvisor) { 3 validateIntroductionAdvisor((IntroductionAdvisor) advisor); 4 } 5 addAdvisorInternal(pos, advisor); 6 }
(3)步驟8:進行獲取代理操做。
咱們再回到AbstractAutoProxyCreator.createProxy方法。最後一句代碼:return proxyFactory.getProxy(getProxyClassLoader());進行解析最重要的一步就是代理類的建立和處理,Spring委託給了ProxyFactory去處理。咱們進入ProxyFactory類(package org.springframework.aop.framework)中的getProxy函數。
1 public Object getProxy() { 2 // 調用了ProxyCreatorSupport的createAopProxy()方法建立一個AopProxy對象 3 // 而後調用AopProxy對象的getProxy方法 4 return createAopProxy().getProxy(); 5 }
其中就一句話return createAopProxy().getProxy();。createAopProxy 方法沒有在ProxyFactory類中定義,createAopProxy方法在其父類ProxyCreatorSupport(package org.springframework.aop.framework)中定義了,進入其代碼:
1 protected final synchronized AopProxy createAopProxy() { 2 if (!this.active) { 3 activate(); 4 } 5 // 實際就是使用DefaultAopProxyFactory來建立一個代理對象 6 // 能夠看到在調用createAopProxy方法時,傳入的參數是this 7 // 這是由於ProxyCreatorSupport自己就保存了建立整個代理對象所須要的配置信息 8 return getAopProxyFactory().createAopProxy(this); 9 }
核心就一句代碼return getAopProxyFactory().createAopProxy(this)。實際用的是AopProxyFactory類的createAopProxy方法。AopProxyFactory只是一個接口,DefaultAopProxyFactory(package org.springframework.aop.framework)是AopProxyFactory默認實現類,核心函數createAopProxy。因此實際上是調用了DefaultAopProxyFactory類的createAopProxy方法。
1 @Override 2 // 就是經過AOP相關的配置信息來決定究竟是使用cglib代理仍是jdk代理 3 public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { 4 // 若是開啓了優化,或者ProxyTargetClass設置爲true 5 // 或者沒有提供代理類須要實現的接口,那麼使用cglib代理 6 // 在前面分析參數的時候已經說過了 7 // 默認狀況下Optimize都爲false,也不建議設置爲true,由於會進行一些侵入性的優化 8 // 除非你對cglib的優化很是瞭解,不然不建議開啓 9 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { 10 Class<?> targetClass = config.getTargetClass(); 11 if (targetClass == null) { 12 throw new AopConfigException("TargetSource cannot determine target class: " + 13 "Either an interface or a target is required for proxy creation."); 14 } 15 // 須要注意的是,若是須要代理的類自己就是一個接口 16 // 或者須要被代理的類自己就是一個經過jdk動態代理生成的類 17 // 那麼無論如何設置都會使用jdk動態代理 18 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { 19 return new JdkDynamicAopProxy(config); 20 } 21 return new ObjenesisCglibAopProxy(config); 22 } 23 // 不然都是jdk代理 24 else { 25 return new JdkDynamicAopProxy(config); 26 } 27 }
至此完成了代理的建立。
(四)織入
Spring主要使用JDK動態代理,因此先回顧性JDK動態代理的原理(詳見上一節JDK動態代理)。
Java動態代理機制中有兩個重要的接口和類:
(1)接口InvocationHandler:動態代理類的調用處理程序。
(2)Proxy:動態代理類,Proxy類就是用來建立一個代理對象的類,
Java動態代理的步驟:
一、建立目標類(委託類)的接口
二、建立目標類(委託類)
三、定義一個代理類的調用處理程序。該程序必須實現接口InvocationHandler,且必須實現接口的invoke方法。
四、經過Proxy的靜態方法newProxyInstance()建立一個代理對象。
五、經過代理對象調用委託類對象的方法。
其實Proxy類只是一個鏈接橋,把代理(InvocationHandler)與被代理類關聯起來,真正處理事情的是InvocaHandler。InvocationHandler接口中的invoke方法在代理類中是動態實現的,當咱們經過動態代理調用一個方法的時候,這個方法的調用會被轉發到到調用處理程序的invoke方法中。
Spring的AOP實現也是用了Proxy和InvocationHandler這兩個東西。JDK代理中InvocationHandler的建立是最爲核心的。在自定義的InvocationHandler中須要重寫3個函數。(1)構造函數,將代理的對象傳入。(2)invoke方法,此方法中實現了AOP加強的全部邏輯。(3)getProxy方法。
上面咱們分析了建立代理最終調用了DefaultAopProxyFactory類的createAopProxy方法,若是使用的是JDK動態代理,其代碼爲return new JdkDynamicAopProxy(config);。 咱們進入JdkDynamicAopProxy類(package org.springframework.aop.framework)。這個類就是用來生成jdk動態代理。能夠看到這個類自己就是一個InvocationHandler,這意味着當調用代理對象中的方法時,最終會調用到JdkDynamicAopProxy的invoke方法。
重點看其getProxy函數和invoke函數。
1 public Object getProxy(@Nullable ClassLoader classLoader) { 2 if (logger.isTraceEnabled()) { 3 logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); 4 } 5 // 這裏獲取到代理類須要實現的全部的接口 6 Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); 7 // 須要明確是否在接口定義了hashCode以及equals方法 8 // 若是接口中沒有定義,那麼在調用代理對象的equals方法的時候 9 // 若是兩個對象相等,那麼意味着它們的目標對象,通知以及實現的接口都相同 10 findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); 11 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 12 }
JDKProxy的使用關鍵是建立自定義的InvocationHandler,InvocationHandler中包含了須要覆蓋的getProxy,上述方法就是完成了這個操做。JdkDynamicAopProxy實現了接口AopProxy、InvocationHandler和Serializable。InvocationHandler除了getProxy還有invoke函數,JdkDynamicAopProxy類將其核心邏輯寫在了這個方法中。
1 /** 2 * Implementation of {@code InvocationHandler.invoke}. 3 * <p>Callers will see exactly the exception thrown by the target, 4 * unless a hook method throws an exception. 5 */ 6 @Override 7 @Nullable 8 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 9 Object oldProxy = null; 10 boolean setProxyContext = false; 11 12 TargetSource targetSource = this.advised.targetSource; 13 Object target = null; 14 15 try { 16 // 首先處理的是hashCode跟equals方法,若是接口中沒有定義這兩個方法,那麼會調用本類中定義的equals方法 17 // equals方法的處理。只有當兩個類的目標對象,通知以及實現的接口都相等的狀況下equals纔會返回true 18 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { 19 // The target does not implement the equals(Object) method itself. 20 return equals(args[0]); 21 } 22 //hash方法的處理 23 else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { 24 // The target does not implement the hashCode() method itself. 25 return hashCode(); 26 } 27 // 也就是說咱們調用的是DecoratingProxy這個接口中的方法 28 // 這個接口中只定義了一個getDecoratedClass方法,用於獲取到 29 // 最終的目標對象,在方法實現中會經過一個while循環來不斷接近 30 // 最終的目標對象,直到獲得的目標對象不是一個被代理的對象纔會返回 31 else if (method.getDeclaringClass() == DecoratingProxy.class) { 32 // There is only getDecoratedClass() declared -> dispatch to proxy config. 33 return AopProxyUtils.ultimateTargetClass(this.advised); 34 } 35 // 說明調用的是Advised接口中的方法,這裏只是單純的進行反射調用 36 else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && 37 method.getDeclaringClass().isAssignableFrom(Advised.class)) { 38 // Service invocations on ProxyConfig with the proxy config... 39 return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); 40 } 41 42 Object retVal; 43 44 //有時候目標對象內部的自我調用將沒法實施切面中的加強則須要經過此屬性暴露代理 45 // 將代理類暴露到線程上下文中,調用AopContext.setCurrentProxy方法將其放入到一個threadLocal中 46 if (this.advised.exposeProxy) { 47 // Make invocation available if necessary. 48 oldProxy = AopContext.setCurrentProxy(proxy); 49 setProxyContext = true; 50 } 51 52 // 接下來就是真正的執行代理邏輯了 53 target = targetSource.getTarget(); 54 Class<?> targetClass = (target != null ? target.getClass() : null); 55 56 // 獲取當前方法的攔截器鏈 57 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 58 59 if (chain.isEmpty()) { 60 //若是沒有發現任何攔截器鏈那麼直接調用切點方法 61 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); 62 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); 63 } 64 // 不然開始執行整個鏈條 65 else { 66 //將攔截器封裝在ReflectiveMethodInvocation以便於使用期proceed進行連接表用攔截器 67 MethodInvocation invocation = 68 new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); 69 //執行攔截器鏈 70 retVal = invocation.proceed(); 71 } 72 73 // Massage return value if necessary. 74 // 這裏是處理一種特殊狀況,就是當執行的方法返回值爲this的狀況 75 // 這種狀況下,須要返回當前的代理對象而不是目標對象 76 Class<?> returnType = method.getReturnType(); 77 if (retVal != null && retVal == target && 78 returnType != Object.class && returnType.isInstance(proxy) && 79 !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { 80 // Special case: it returned "this" and the return type of the method 81 // is type-compatible. Note that we can't help if the target sets 82 // a reference to itself in another returned object. 83 retVal = proxy; 84 } 85 else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { 86 throw new AopInvocationException( 87 "Null return value from advice does not match primitive return type for: " + method); 88 } 89 return retVal; 90 } 91 finally { 92 if (target != null && !targetSource.isStatic()) { 93 // Must have come from TargetSource. 94 targetSource.releaseTarget(target); 95 } 96 if (setProxyContext) { 97 // Restore old proxy. 98 AopContext.setCurrentProxy(oldProxy); 99 } 100 } 101 }
上面的函數最主要的工做是建立了一個攔截器鏈,並使用ReflectiveMethodInvocation類進行了鏈的封裝,而在ReflectiveMethodInvocation類的proceed方法中實現了攔截器的逐一調用。咱們繼續看proceed方法是怎麼實現前置加強在目標方法前調用,後置加強在目標方法後調用的邏輯。
ReflectiveMethodInvocation(package org.springframework.aop.framework包中)是一個核心類,激發攔截鏈工做實現。該類實現了aop聯盟的MethodInvocation,間接實現了Invocation和Joinpoint。咱們進入其proceed函數:
1 @Override 2 @Nullable 3 public Object proceed() throws Throwable { 4 // We start with an index of -1 and increment early. 5 //執行完全部加強後執行切點方法 6 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { 7 return invokeJoinpoint(); 8 } 9 10 //獲取下一個要執行的攔截器 11 Object interceptorOrInterceptionAdvice = 12 this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); 13 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { 14 // Evaluate dynamic method matcher here: static part will already have 15 // been evaluated and found to match. 16 //動態匹配 17 InterceptorAndDynamicMethodMatcher dm = 18 (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; 19 Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass()); 20 if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) { 21 return dm.interceptor.invoke(this); 22 } 23 else { 24 // Dynamic matching failed. 25 // Skip this interceptor and invoke the next in the chain. 26 //不匹配就不執行攔截器 27 return proceed(); 28 } 29 } 30 else { 31 // It's an interceptor, so we just invoke it: The pointcut will have 32 // been evaluated statically before this object was constructed. 33 //普通攔截器,直接調用攔截器。將this做爲參賽傳入以保障當前實例中調用鏈的執行。 34 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); 35 } 36 }
在proceed方法中,ReflectiveMethodInvocation的主要職責是維護了調用的計數器,記錄着當前調用連接的位置,以即可以有序的進行下去。
本文參考了 郝佳《Spring源碼深度解析》第七章AOP及博客園、CSDN部分文獻。
博衆家之所長,集羣英之薈萃。遴選各IT領域精品雄文!
歡迎關注「IT架構精選」