淺析Spring AOP
本文大概:1200字閱讀需要:15分鐘
Aop(Aspect-OrientedProgramming)面向切面編程是對OOP的補充,專註於系統中不同模塊統一的處理邏輯,比如事務管理,日誌管理,緩存等系統級服務。
眾所周知,SpringAop基於代理實現的,比如JDK動態代理和CGLIB代理。
既然如此,在這之前先初探JDK動態代理。
那麼如何使用JDK動態代理呢?
1):創建實現了InvocationHandler介面的類,實現invoke方法,該方法將在與之關聯的代理類方法調用的時候執行
2):通過Proxy.newProxyInstance()方法返回代理對象
target為需要代理的目標對象,一般實現了某個介面,本例中Pojo介面只有兩個簡單方法
SimplePojo實現了Pojo介面,當調用bar(),foo()方法時,最終會調用invoke方法,實現攔截的邏輯。
為什麼最終會調用invoke方法呢?
主要原因還在於Proxy.newProxyInstance()返回了一個代理類,該類以$Proxy開頭,並實現了目標對象所實現的介面,並把實現了InvocationHandler的類作為代理類的構造參數;
如上例子,會產生一個name為$Proxy0的類,同時實現了Pojo介面。
因此,從生成的class可以看出,當調用foo(),bar()方法時,最終會調用invoke方法,可以在目標方法的調用前後實現其他的業務邏輯。
分析完JDK動態代理,下面正式進入springAop的世界,對於如何使用AOP,本文不做過多的分析,並以註解的形式進行淺析。
這一切又是怎麼發生了呢?
整個過程大致分為四步:
1.註冊Aop處理器
Spring容器在載入配置文件解析標籤時,會在spring-aop.jar包下的META-INF文件下找到spring.handlers的properties文件
該handler會註冊針對標籤的解析器
其主要作用即向容器注入處理@Aspect註解的bean
AnnotationAwareAspectJAutoProxyCreator的類層次圖如下圖所示:
可以看出該類實現了BeanPostProcessor介面,Spring文檔對該介面的解釋即允許對bean進行修改,比如返回代理。
而Spring容器在初始化bean的時候會調用beanpost processor(bean的創建過程本文不做分析),本文最後附上了BeanPostProcessor的一個應用。
2.查找容器內所有的Advisors
該邏輯在AnnotationAwareAspectJAutoProxyCreator.findCadidateAdvisors()方法,其主要邏輯即是尋找容器中標有@Aspect註解的類以及配置文件中的
@Aspect的處理邏輯大概概括為:提取標有@Aspect註解類的方法(排除了標有@PonitCut註解的方法),對標記有@Aroud,@Before,@After,@AfterReturing,@AfterThrowing的方法封裝為Advisor.並且返回的是有序的集合,順序分別是@Around,@Before,@After,@AfterReturning,@AfterThrowing。此時即提取了所有的Advisor.
3.查找符合條件的bean
findAdvisorsThatCanApply的主要邏輯是尋找匹配當前bean的Advisor.從編碼的角度來看,即當前bean匹配Advisor的切入點表達式;比如:execution(*com.dr.demo..*.*(..)),即com.dr.demo包以及其子包下的類的任何方法都應進行增強。
4.創建代理對象
前面第一點提到AnnotationAwareAspectJAutoProxyCreator實現了BeanProcessor介面,此處即對容器里符合條件的bean創建代理。
Spring提供2種方式實現代理:CGLIB代理以及JDK代理,比如設置了proxy-target-class,則會使用Cglib代理,本文以JDK動態代理為例,分析創建代理對象的過程。
本文開篇即分析了JDK動態代理原理,以及使用方式,看看spring又是如何實現呢?
JdkDynamicAopProxy同樣實現了InvocationHandler,其getProxy方法返回代理對象,代理的介面即為第3步找到的Advisor.
因此,當從spring容器里獲取對象時,其實質是返回的代理對象;當執行方法時,均會執行invoke方法,以下代碼片段是invoke方法的一部分,封裝攔截器鏈(不止一個增加),隨後遍歷攔截器鏈,執行攔截器方法,直到攔截器鏈執行完畢,在執行目標方法。
小結:以上只是對springaop粗略的分析,springaop的實現極為複雜,比如切入點表達的提取,以及joinPoint與PointCut的匹配等內容。
參考文獻:
https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#aop-introduction-defn
※快一點,再快一點
※今天我們來聊一聊運動這件事
※淺談 golang channel
※從InnoDB了解MVCC
※需求分析的套與路
TAG:點融黑幫 |