詳解Spring Aop實例之AspectJ注解配置
上篇《Spring Aop實例之xml配置》中,講解了xml配置方式,今天來說說AspectJ注解方式去配置spring aop。
依舊采用的jdk,接口和實現(xiàn)類代碼請參考上篇博文。主要是將Aspect類分享一下:
package com.tgb.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.DeclareParents;
import org.aspectj.lang.annotation.Pointcut;
/**
* 測試after,before,around,throwing,returning Advice.
* @author Admin
*
*/
@Aspect
public class AspceJAdvice {
/**
* Pointcut
* 定義Pointcut,Pointcut的名稱為aspectjMethod(),此方法沒有返回值和參數(shù)
* 該方法就是一個標識,不進行調(diào)用
*/
@Pointcut("execution(* find*(..))")
private void aspectjMethod(){};
/**
* Before
* 在核心業(yè)務(wù)執(zhí)行前執(zhí)行,不能阻止核心業(yè)務(wù)的調(diào)用。
* @param joinPoint
*/
@Before("aspectjMethod()")
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("-----beforeAdvice().invoke-----");
System.out.println(" 此處意在執(zhí)行核心業(yè)務(wù)邏輯前,做一些安全性的判斷等等");
System.out.println(" 可通過joinPoint來獲取所需要的內(nèi)容");
System.out.println("-----End of beforeAdvice()------");
}
/**
* After
* 核心業(yè)務(wù)邏輯退出后(包括正常執(zhí)行結(jié)束和異常退出),執(zhí)行此Advice
* @param joinPoint
*/
@After(value = "aspectjMethod()")
public void afterAdvice(JoinPoint joinPoint) {
System.out.println("-----afterAdvice().invoke-----");
System.out.println(" 此處意在執(zhí)行核心業(yè)務(wù)邏輯之后,做一些日志記錄操作等等");
System.out.println(" 可通過joinPoint來獲取所需要的內(nèi)容");
System.out.println("-----End of afterAdvice()------");
}
/**
* Around
* 手動控制調(diào)用核心業(yè)務(wù)邏輯,以及調(diào)用前和調(diào)用后的處理,
*
* 注意:當核心業(yè)務(wù)拋異常后,立即退出,轉(zhuǎn)向AfterAdvice
* 執(zhí)行完AfterAdvice,再轉(zhuǎn)到ThrowingAdvice
* @param pjp
* @return
* @throws Throwable
*/
@Around(value = "aspectjMethod()")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("-----aroundAdvice().invoke-----");
System.out.println(" 此處可以做類似于Before Advice的事情");
//調(diào)用核心邏輯
Object retVal = pjp.proceed();
System.out.println(" 此處可以做類似于After Advice的事情");
System.out.println("-----End of aroundAdvice()------");
return retVal;
}
/**
* AfterReturning
* 核心業(yè)務(wù)邏輯調(diào)用正常退出后,不管是否有返回值,正常退出后,均執(zhí)行此Advice
* @param joinPoint
*/
@AfterReturning(value = "aspectjMethod()", returning = "retVal")
public void afterReturningAdvice(JoinPoint joinPoint, String retVal) {
System.out.println("-----afterReturningAdvice().invoke-----");
System.out.println("Return Value: " + retVal);
System.out.println(" 此處可以對返回值做進一步處理");
System.out.println(" 可通過joinPoint來獲取所需要的內(nèi)容");
System.out.println("-----End of afterReturningAdvice()------");
}
/**
* 核心業(yè)務(wù)邏輯調(diào)用異常退出后,執(zhí)行此Advice,處理錯誤信息
*
* 注意:執(zhí)行順序在Around Advice之后
* @param joinPoint
* @param ex
*/
@AfterThrowing(value = "aspectjMethod()", throwing = "ex")
public void afterThrowingAdvice(JoinPoint joinPoint, Exception ex) {
System.out.println("-----afterThrowingAdvice().invoke-----");
System.out.println(" 錯誤信息:"+ex.getMessage());
System.out.println(" 此處意在執(zhí)行核心業(yè)務(wù)邏輯出錯時,捕獲異常,并可做一些日志記錄操作等等");
System.out.println(" 可通過joinPoint來獲取所需要的內(nèi)容");
System.out.println("-----End of afterThrowingAdvice()------");
}
}
application-config.xml中,只需要配置業(yè)務(wù)邏輯bean和Aspect bean,并啟用Aspect注解即可:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<!-- 啟用AspectJ對Annotation的支持 -->
<aop:aspectj-autoproxy/>
<bean id="userManager" class="com.tgb.aop.UserManagerImpl"/>
<bean id="aspcejHandler" class="com.tgb.aop.AspceJAdvice"/>
</beans> 結(jié)果如圖:


通過測試的發(fā)現(xiàn)AroundAdvice、BeforeAdvice、AfterAdvice、ReturningAdvice的執(zhí)行順序是根據(jù)注解的順序而定的。但是有時候修改了順序,結(jié)果卻沒有變化,可能是緩存的緣故。前幾天我也遇到了這樣的問題,不過今天再測試了一下,發(fā)現(xiàn)執(zhí)行順序又跟注解的順序一致了。
xml 和 Annotation 注解都可以作為配置項,對Spring AoP進行配置管理,那么它們各自都有什么優(yōu)缺點呢?
首先說說 xml 。目前 web 應(yīng)用中幾乎都使用 xml 作為配置項,例如我們常用的框架 Struts、Spring、hibernate 等等都采用 xml 作為配置。xml 之所以這么流行,是因為它的很多優(yōu)點是其它技術(shù)的配置所無法替代的:
- xml 作為可擴展標記語言最大的優(yōu)勢在于開發(fā)者能夠為軟件量身定制適用的標記,使代碼更加通俗易懂。
- 利用 xml 配置能使軟件更具擴展性。例如 Spring 將 class 間的依賴配置在 xml 中,最大限度地提升應(yīng)用的可擴展性。
- 具有成熟的驗證機制確保程序正確性。利用 Schema 或 DTD 可以對 xml 的正確性進行驗證,避免了非法的配置導(dǎo)致應(yīng)用程序出錯。
- 修改配置而無需變動現(xiàn)有程序。
雖然有如此多的好處,但畢竟沒有什么萬能的東西,xml 也有自身的缺點。
- 需要解析工具或類庫的支持。
- 解析 xml 勢必會影響應(yīng)用程序性能,占用系統(tǒng)資源。
- 配置文件過多導(dǎo)致管理變得困難。
- 編譯期無法對其配置項的正確性進行驗證,或要查錯只能在運行期。
- IDE 無法驗證配置項的正確無能為力。
- 查錯變得困難。往往配置的一個手誤導(dǎo)致莫名其妙的錯誤。
- 開發(fā)人員不得不同時維護代碼和配置文件,開發(fā)效率變得低下。
- 配置項與代碼間存在潛規(guī)則。改變了任何一方都有可能影響另外一方。
讓我們來看看 Annotation 的優(yōu)點。
- 保存在 class 文件中,降低維護成本。
- 無需工具支持,無需解析。
- 編譯期驗證正確性,查錯變得容易。
- 提升開發(fā)效率。
同樣 Annotation 也不是萬能的,它也有很多缺點。
- 若要對配置項進行修改,不得不修改 Java 文件,重新編譯打包應(yīng)用。
- 配置項編碼在 Java 文件中,可擴展性差。
總結(jié):沒有一個事物是萬能的,同樣 xml 和 Java Annotation 都有各自的優(yōu)缺點。通過以上對比,細心的讀者可能已經(jīng)發(fā)現(xiàn)它們的優(yōu)缺點恰恰是互補的。xml 的強項是 Annotation 所不具備的,而 Annotation 的優(yōu)勢也是 xml 所欠缺的。這也正是時下流行的 xml + Annotation 配置的原因所在。平衡才是王道呀!
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Spring?Boot實現(xiàn)JWT?token自動續(xù)期的實現(xiàn)
本文主要介紹了Spring?Boot實現(xiàn)JWT?token自動續(xù)期,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12
@FeignClient?實現(xiàn)簡便http請求封裝方式
這篇文章主要介紹了@FeignClient?實現(xiàn)簡便http請求封裝方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
Java中從Integer到Date的轉(zhuǎn)換方法
這篇文章主要介紹了Java中integer怎么轉(zhuǎn)換date,在Java中,如果我們有一個Integer類型的數(shù)據(jù),想要將其轉(zhuǎn)換為Date類型,本文給大家介紹了實現(xiàn)方法,并通過代碼示例講解的非常詳細,需要的朋友可以參考下2024-05-05
Spring?Boot實現(xiàn)微信掃碼登錄功能流程分析
這篇文章主要介紹了Spring?Boot?實現(xiàn)微信掃碼登錄功能,介紹了授權(quán)流程代碼和用戶登錄和登出的操作代碼,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-04-04
java 解決異常 2 字節(jié)的 UTF-8 序列的字節(jié)2 無效的問題
這篇文章主要介紹了java 解決異常 2 字節(jié)的 UTF-8 序列的字節(jié) 2 無效的問題的相關(guān)資料,需要的朋友可以參考下2016-12-12

