AspectJ是一個面向切面編程的框架,使用AspectJ不需要改動Spring配置文件,就可以實現Spring AOP功能。本篇結合實際案例詳細講述使用AspectJ實現AOP功能。通過本篇的學習,可以解決如下問題。
● 使用AspectJ技術的背景是什麼?
● 在不修改原有業務代碼的情況下,如何設置業務攔截點?
1、 使用AspectJ技術的背景
在使用AspectJ之前,需要確定項目已經引入了AspectJ相關Jar包,並且AspectJ的版本要兼容JDK、Spring框架的版本,使用不兼容的版本會導致程序報錯。
課程案例SpringProgram項目使用的JDK版本是1.8,Spring框架版本是5.08。需要引入的AspectJ相關Jar包如下所示。
● aspectj-1.8.9
● aspectjweaver-1.8.9
關於AOP實現原理在《詳解Spring框架的AOP機制》一文中已經詳細描述,這裡不再贅述。不過本文的AOP項目案例還是借鑑《詳解Spring框架的AOP機制》一文中的案例。因為Spring框架提供了AspectJ 註解方法和基於XML架構的方法來實現AOP,在《詳解Spring框架的AOP機制》中,重點介紹了基於XML架構的方法來實現AOP,本文將重點介紹利用AspectJ 註解方法實現AOP。用同一個案例採用兩種不同的實現方法,既可以加深對AOP的理解,也可以對兩種實現技術進行對比,可以選擇適合自己的一種技術來實現AOP。
在課程案例SpringProgram項目中,一個業務流程是校長通過郵件發送上課通知給老師。校長執行該業務時,業務系統並沒有對老師進行驗證。現在要求校長在發送通知之前,需要對老師進行用戶驗證。
具體要求是在儘量不改變原有業務代碼的情況下,加入老師驗證功能。原有業務代碼如下。
分析上面的業務代碼,可以考慮在執行setTeacher之前加入老師的驗證方法,並將老師對象teacherZhang作為參數傳給驗證方法。如果能夠修改業務代碼,可以直接在setTeacher方法之前加入VerifyTeacher驗證方法。
由於各種原因,不允許修改原有的業務代碼。在這種情況下,可以採用AOP技術,攔截setTeacher方法,在setTeacher方法執行之前、執行之後、拋出異常之後執行攔截方法。攔截方法所在類的稱為切面,攔截方法稱為切入點。如下圖所示。
2、使用Aspectj攔截setTeacher方法
AspectVerifyUser類用於驗證老師身份,如果不加Aspecj註解,AspectVerifyUser類只是一個普通的Java類,不能被AOP調度使用。要使AspectVerifyUser類作為切面使用並攔截setTeacher方法,實現執行setTeacher方法之前先執行VerifyTeacher方法,在setTeacher方法執行成功後,再執行AfterSetTeacher方法。就需要在AspectVerifyUser類中添加Aspecj註解。
添加@Aspect註解
在類頭部加@Aspect註解,使AspectVerifyUser類成為切面類,並被AOP識別和加載。作用類似於在Spring配置文件中的AOP標籤<aop:config>。
添加 @Pointcut註解
在類方法頭部加@Pointcut註解,使該方法稱為一個切入點。@Pointcut註解的execution表達式定義該方法在什麼位置切入。
例如:
@Pointcut註解指示AOP將VerifyUser()方法作為切入點,切入到AopEmailNotice類的setTeacher位置,傳入的參數為任意類型和數量,VerifyUser()為空函數,實際執行的函數通過@Before、@After、@Around等註解與VerifyUser()方法關聯。
再如:
@Pointcut註解指示AOP將VerifyUser()方法作為切入點,切入到com.milihua.springprogram.notice包及子包下所有的類及類中所有的方法。
又如:
@Pointcut註解指示AOP將VerifyUser()方法作為切入點,切入到com.milihua.springprogram.notice包下所有的類及類中所有的方法。
添加 @{ADVICE-NAME}註解
@{ADVICE-NAME}為聲明建議註解,也可以稱之為通知註解。該註解添加到實際執行函數的頭部,並與切入點的名稱進行關聯。
@{ADVICE-NAME}有五種註解,分別是@Before、@After、@Around、@AfterReturning、@AfterThrowing。被@Before註解的方法在被切入方法執行之前執行;被@After註解的方法在被切入方法執行之後執行,不考慮是否執行成功;被@AfterReturning註解的方法在被切入方法執行成功之後執行,當被切入方法發生異常時,該方法不被執行;被@Around註解的方法在被切入方法執行之前和執行之後都執行;被@AfterThrowing註解的方法,只有當被切入方法執行過程發生異常時才會執行。
例如:
VerifyTeacher方法頭部被@Before("VerifyUser()")註解,該方法在被切入的setTeacher方法之前執行。
獲取通知參數
切入方法如何獲取被切入方法傳遞過來的參數呢?例如,AspectVerifyUser類的VerifyTeacher方法切入到AopEmailNotice類的setTeacher方法,VerifyTeacher需要獲取setTeacher方法的AopTeacher類參數,用於對老師進行用戶驗證。
AOP使用org.aspectj.lang.JoinPoint類型,用於獲取被切入點傳入的參數,任何切入方法的第一個參數都可以是JoinPoint。JoinPoint結構如下。
其中,getArgs方法可以獲取被切入點方法參數列表,根據參數列表可以獲取傳入的參數。
在課程案例SpringProgram項目中,添加aspec.xml,配置AspectVerifyUser類。
在課程案例SpringProgram項目中,添加測試類。
課程小結
(1)本篇探討了使用AspectJ技術的背景。當原有業務流程需要添加事務處理、安全控制、性能統計、異常處理等功能時,可以使用AspectJ技術在不修改原有業務代碼的情況下,將上述功能切入到業務流程中;在構建新的系統時,也可以將上述功能獨立考慮,再通過AspectJ技術將它們集成到系統中。
(2)本篇也通過案例講述了應用AspectJ技術實現AOP的過程,具體實現步驟是:首先編寫需要切入業務流程的獨立模塊(也稱為切面)和切入點(模塊中的方法),並添加AspectJ相關註解,確定切入的位置;然後在Spring配置文件中配置新添加的切面Bean,無需配置AOP信息;最後編寫測試代碼。