您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關如何使用Spring開啟注解AOP支持放置的位置,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
放在springmvc的aop,需要在springmvc的配置文件中寫開啟aop,而不是spring的配置文件
最近使用aop來記錄controller的日志.
但是發現沒有起作用.
后來發現是因為我的 aop 是寫在controller層(在springmvc的容器中 -web中)
而開啟aop配置卻寫在spring(applicationContext.xml)中
所以不起作用,需要在springmvc.xml的配置文件中也開啟才行
要在 Spring 應用中使用 AspectJ 注解,需要如下支持:
1. 在 classpath 下包含 AspectJ 類庫:aopalliance.jar、aspectj.weaver.jar 和 spring-aspects.jar
2. 將 aop Schema 添加到 Bean 配置文件 <beans> 根元素中。
3. 在 Bean 配置文件中定義一個空的 XML 元素 <aop:aspectj-autoproxy><aop:aspectj-autoproxy/>
注:當 Spring IOC 容器偵測到 Bean 配置文件中的<aop:aspectj-autoproxy><aop:aspectj-autoproxy/> 元素時,會自動為與 AspectJ 切面匹配的 Bean 創建代理。
要在 Spring 中聲明 AspectJ 切面,只需要在 IOC 容器中將切面聲明為 Bean 實例。當在 Spring IOC 容器中初始化 AspectJ 切面之后,Spring IOC 容器就會為那些與 AspectJ 切面相匹配的 Bean 創建代理。
在 AspectJ 注解中,切面只是一個帶有 @Aspect 注解的 Java 類。通知是標注有某種注解的簡單的 Java 方法。
AspectJ 支持 5 種類型的通知注解:
@Before
:前置通知,在方法執行之前執行
@After
:后置通知,在方法執行之后執行
@AfterRunning
:返回通知,在方法返回結果之后執行
@AfterThrowing
:異常通知,在方法拋出異常之后
@Around
:環繞通知,圍繞著方法執行
前置通知:在方法執行之前執行的通知。
前置通知使用 @Before 注解,并將切入點表達式的值作為注解值。
/** * 把這個類聲明為一個切面: * 1. 使用注解“@Repository”把該類放入到IOC容器中 * 2. 使用注解“@Aspect”把該類聲明為一個切面 * * 設置切面的優先級: * 3. 使用注解“@Order(number)”指定前面的優先級,值越小,優先級越高 */ @Order(1) @Aspect @Repository public class DaoLogAspect { /** * 聲明該方法是一個前置通知:在目標方法開始之前執行 * '@Before'標識這個方法是個前置通知,切點表達式表示執行 UserDao類的 insert(User user) 方法. */ @Before("execution(public xyz.huning.spring4.aop.dao.User xyz.huning.spring4.aop.dao.impl.UserDao.insert(xyz.huning.spring4.aop.dao.User))") public void beforeInsert() { System.out.println("--beforeInsert------------"); } }
最典型的切入點表達式是根據方法的簽名來匹配各種方法:
execution * xyz.huning.spring4.aop.dao.impl.UserDao.*(..)
:匹配UserDao中聲明的所有方法,第一個 * 代表任意修飾符及任意返回值。第二個 * 代表任意方法。 .. 匹配任意數量的參數。若目標類與接口與該切面在同一個包中,可以省略包名。
execution public * UserDao.*(..)
:匹配 UserDao類的所有公有方法。
execution public double UserDao.*(..)
:匹配 UserDao中返回 double 類型數值的方法。
execution public double UserDao.*(double, ..)
:匹配第一個參數為 double 類型的方法, .. 匹配任意數量任意類型的參數。
execution public double UserDao.*(double,double)
:匹配參數類型為 double,double 類型的方法。
在 AspectJ 中,切入點表達式可以通過操作符 &&,||,! 結合起來。
/** * 合并切入點表達式 * 在 AspectJ 中,切入點表達式可以通過操作符 &&,||,! 結合起來。 */ @Pointcut("execution(* *.insert(..)) || execution(* *.delete(..))") public void insertDeleteJoinPoint(){}
可以在通知方法中聲明一個類型為 JoinPoint 的參數。然后就能訪問鏈接細節。如方法名稱和參數值。
/** * 聲明該方法是一個前置通知:在目標方法開始之前執行 */ @Before("execution(public xyz.huning.spring4.aop.dao.User xyz.huning.spring4.aop.dao.impl.UserDao.insert(xyz.huning.spring4.aop.dao.User))") public void beforeInsert(JoinPoint joinPoint) { System.out.println("--beforeInsert with joinPoint------------"); //獲取方法名稱 String methodName = joinPoint.getSignature().getName(); //獲取參數值 String args = Arrays.toString(joinPoint.getArgs()); System.out.println("Taget method: " + methodName); System.out.println("Taget method args: " + args); }
后置通知是在連接點完成之后執行的, 即連接點返回結果或者拋出異常的時候,下面的后置通知記錄了方法的終止。
一個切面可以包括一個或者多個通知。
/** * 聲明該方法是一個后置通知:在目標方法開始之后執行(即使目標方法執行出現異常也會執行) * 后置通知中不能訪問目標方法的執行結果 */ @After("execution(public xyz.huning.spring4.aop.dao.User xyz.huning.spring4.aop.dao.impl.UserDao.insert(xyz.huning.spring4.aop.dao.User))") public void afterInsert() { System.out.println("--afterInsert------------"); }
無論連接點是正常返回還是拋出異常,后置通知都會執行。如果只想在連接點返回的時候記錄日志,應使用返回通知代替后置通知。在返回通知中,只要將 returning 屬性添加到 @AfterReturning 注解中,就可以訪問連接點的返回值。該屬性的值即為用來傳入返回值的參數名稱。
必須在通知方法的簽名中添加一個同名參數。在運行時,Spring AOP 會通過這個參數傳遞返回值。原始的切點表達式需要出現在 pointcut 屬性中。
/** * 聲明該方法是一個返回通知:在目標方法正常結束之后返回(目標方法執行出現異常時不再執行) * 返回通知可以訪問目標方法的執行結果 */ @AfterReturning(value="execution(* xyz.huning.spring4.aop.dao.impl.UserDao.query(..))",returning="result") public void afterQueryReturning(JoinPoint joinPoint,Object result) { System.out.println("--afterQueryReturning with joinPoint and result------------"); String methodName = joinPoint.getSignature().getName(); String args = Arrays.toString(joinPoint.getArgs()); System.out.println("Taget method: " + methodName); System.out.println("Taget method args: " + args); System.out.println("Taget method execute result: " + result); }
只在連接點拋出異常時才執行異常通知,將 throwing 屬性添加到 @AfterThrowing 注解中,也可以訪問連接點拋出的異常。Throwable 是所有錯誤和異常類的超類。
所以在異常通知方法可以捕獲到任何錯誤和異常。如果只對某種特殊的異常類型感興趣,可以將參數聲明為其他異常的參數類型。然后通知就只在拋出這個類型及其子類的異常時才被執行。
/** * 聲明該方法是一個異常通知:在目標方法出現異常時執行此方法 * 異常通知可以訪問目標方法中的異常對象,且可以指定在出現特定異常時再執行通知代碼 */ @AfterThrowing(value="execution(* xyz.huning.spring4.aop.dao.impl.UserDao.*(..))",throwing="e") public void afterAllThrowing(JoinPoint joinPoint,Exception e) { System.out.println("--afterAllThrowing with throwing------------"); System.out.println("Taget method execute exception: " + e); } /** * 指定在出現特定異常時再執行通知代碼 */ @AfterThrowing(value="execution(* xyz.huning.spring4.aop.dao.impl.UserDao.*(..))",throwing="e") public void afterAllThrowing(JoinPoint joinPoint,NullPointerException e) { System.out.println("--afterAllThrowing with NullPointerException------------"); System.out.println("Taget method execute exception: " + e); }
環繞通知是所有通知類型中功能最為強大的,能夠全面地控制連接點。甚至可以控制是否執行連接點。對于環繞通知來說,連接點的參數類型必須是 ProceedingJoinPoint 。
它是 JoinPoint 的子接口,允許控制何時執行,是否執行連接點。在環繞通知中需要明確調用 ProceedingJoinPoint 的 proceed() 方法來執行被代理的方法。如果忘記這樣做就會導致通知被執行了,但目標方法沒有被執行。
注意:環繞通知的方法需要返回目標方法執行之后的結果,即調用 joinPoint.proceed()的返回值,否則會出現空指針異常。
/** * 環繞通知需要攜帶ProceedingJoinPoint類型的參數 * 環繞通知類似于動態代理的全過程:ProceedingJoinPoint類型的參數可以決定是否執行目標方法 * 且環繞通知必須有返回值,返回值即為目標方法的返回值 */ @Around("execution(* xyz.huning.spring4.aop.dao.impl.UserDao.delete(..))") public Object around(ProceedingJoinPoint pj) { Object result = null; String methodName = pj.getSignature().getName(); try{ //前置通知 System.out.println("The method: " + methodName + "前置通知"); //執行目標方法 result = pj.proceed(); //返回通知 System.out.println("The method: " + methodName + "返回通知"); }catch(Throwable e) { //異常通知 System.out.println("The method: " + methodName + "異常通知: " + e.getMessage()); } //后置通知 System.out.println("The method: " + methodName + "后置通知"); return result; }
在同一個連接點上應用不止一個切面時,除非明確指定,否則它們的優先級是不確定的。
切面的優先級可以通過實現 Ordered 接口或利用 @Order 注解指定。實現 Ordered 接口,,getOrder() 方法的返回值越小,優先級越高。若使用 @Order 注解,序號出現在注解中。
在編寫 AspectJ 切面時,可以直接在通知注解中書寫切入點表達式,但同一個切點表達式可能會在多個通知中重復出現。
在 AspectJ 切面中,可以通過 @Pointcut 注解將一個切入點聲明成簡單的方法。切入點的方法體通常是空的,因為將切入點定義與應用程序邏輯混在一起是不合理的。
切入點方法的訪問控制符同時也控制著這個切入點的可見性。如果切入點要在多個切面中共用,最好將它們集中在一個公共的類中。在這種情況下,它們必須被聲明為 public。
在引入這個切入點時,必須將類名也包括在內。如果類沒有與這個切面放在同一個包中,還必須包含包名。其他通知可以通過方法名稱引入該切入點。
/** * * ************重用切點表達式******************************************************************************** * * 定義一個方法,用于聲明切入點表達式,一般的,該方法中不再不要填土其他的代碼。 * 使用@Pointcut來聲明切入點表達式。 * 同一個類中其他通知直接使用方法名來引用當前的切入點表達式,如:@Before("method()") * 同一個報下其他類中的通知需要在方法名前加類名,如:@Before("class.method()") * 其他包下面類中的通知需要在方法名前加類的全額限定名,如:@AfterReturning(value="package.class.method()",returning="result") * * 第一個星號代表匹配任意修飾符及任意返回值, 第二個星號表示任意方法名稱,參數列表中的兩個點號表示任意數量和類型的參數 */ @Pointcut("execution(* xyz.huning.spring4.aop.dao.impl.UserDao.*(..))") public void userDaoJoinPoint(){}
關于“如何使用Spring開啟注解AOP支持放置的位置”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。