Spring用AspectJ開發(fā)AOP(基于Annotation)
基于 Annotation 的聲明式
在 Spring 中,盡管使用 XML 配置文件可以實(shí)現(xiàn) AOP 開發(fā),但是如果所有的相關(guān)的配置都集中在配置文件中,勢(shì)必會(huì)導(dǎo)致 XML 配置文件過于臃腫,從而給維護(hù)和升級(jí)帶來一定的困難。
為此,AspectJ 框架為 AOP 開發(fā)提供了另一種開發(fā)方式——基于 Annotation 的聲明式。AspectJ 允許使用注解定義切面、切入點(diǎn)和增強(qiáng)處理,而 Spring 框架則可以識(shí)別并根據(jù)這些注解生成 AOP 代理。
關(guān)于 Annotation 注解的介紹如表 1 所示。
表 1 Annotation 注解介紹
名稱 | 說明 |
---|---|
@Aspect | 用于定義一個(gè)切面。 |
@Before | 用于定義前置通知,相當(dāng)于 BeforeAdvice。 |
@AfterReturning | 用于定義后置通知,相當(dāng)于 AfterReturningAdvice。 |
@Around | 用于定義環(huán)繞通知,相當(dāng)于MethodInterceptor。 |
@AfterThrowing | 用于定義拋出通知,相當(dāng)于ThrowAdvice。 |
@After | 用于定義最終final通知,不管是否異常,該通知都會(huì)執(zhí)行。 |
@DeclareParents | 用于定義引介通知,相當(dāng)于IntroductionInterceptor(不要求掌握)。 |
下面使用注解的方式重新實(shí)現(xiàn)《基于XML的聲明式》部分的功能。
1. 創(chuàng)建切面類 MyAspect
在 src 目錄下創(chuàng)建一個(gè)名為 com.mengma.aspectj.annotation 的包,在該包下創(chuàng)建一個(gè)切面類 MyAspect,如下所示。
package com.mengma.aspectj.annotation; 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.Pointcut; import org.springframework.stereotype.Component; //切面類 @Aspect @Component public class MyAspect { // 用于取代:<aop:pointcut // expression="execution(*com.mengma.dao..*.*(..))" id="myPointCut"/> // 要求:方法必須是private,沒有值,名稱自定義,沒有參數(shù) @Pointcut("execution(*com.mengma.dao..*.*(..))") private void myPointCut() { } // 前置通知 @Before("myPointCut()") public void myBefore(JoinPoint joinPoint) { System.out.print("前置通知,目標(biāo):"); System.out.print(joinPoint.getTarget() + "方法名稱:"); System.out.println(joinPoint.getSignature().getName()); } // 后置通知 @AfterReturning(value = "myPointCut()") public void myAfterReturning(JoinPoint joinPoint) { System.out.print("后置通知,方法名稱:" + joinPoint.getSignature().getName()); } // 環(huán)繞通知 @Around("myPointCut()") public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("環(huán)繞開始"); // 開始 Object obj = proceedingJoinPoint.proceed(); // 執(zhí)行當(dāng)前目標(biāo)方法 System.out.println("環(huán)繞結(jié)束"); // 結(jié)束 return obj; } // 異常通知 @AfterThrowing(value = "myPointCut()", throwing = "e") public void myAfterThrowing(JoinPoint joinPoint, Throwable e) { System.out.println("異常通知" + "出錯(cuò)了" + e.getMessage()); } // 最終通知 @After("myPointCut()") public void myAfter() { System.out.println("最終通知"); } }
上述代碼中,第 13 行 @Aspect 注解用于聲明這是一個(gè)切面類,該類作為組件使用,所以要添加 @Component 注解才能生效。第 19 行中 @Poincut 注解用于配置切入點(diǎn),取代 XML 文件中配置切入點(diǎn)的代碼。
在每個(gè)通知相應(yīng)的方法上都添加了注解聲明,并且將切入點(diǎn)方法名“myPointCut”作為參數(shù)傳遞給要執(zhí)行的方法,如需其他參數(shù)(如異常通知的異常參數(shù)),可以根據(jù)代碼提示傳遞相應(yīng)的屬性值。
2. 為目標(biāo)類添加注解
在 com.mengma.dao.CustomerDaoImpl 目標(biāo)類中添加注解 @Repository("customerDao")。
import org.springframework.stereotype.Repository; @Repository("customerDao") public class CustomerDao { public void doSome(){ // int i=1/0; System.out.println("正式業(yè)務(wù)"); } }
3. 創(chuàng)建Spring配置文件
在 com.mengma.aspectj.annotation 包下創(chuàng)建 applicationContext.xml 配置文件,如下所示。
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--掃描含com.mengma包下的所有注解--> <context:component-scan base-package="com.mengma"/> <!-- 使切面開啟自動(dòng)代理 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
上述代碼中,首先導(dǎo)入了 AOP 命名空間及其配套的約束,使切面類中的 @AspectJ 注解能夠正常工作;第 13 行代碼添加了掃描包,使注解生效。需要注意的是,這里還包括目標(biāo)類 com.mengma.dao.CustomerDaoImpl 的注解,所以 base-package 的值為 com.mengma;第 15 行代碼的作用是切面開啟自動(dòng)代理。
4. 創(chuàng)建測(cè)試類
在 com.mengma.aspectj.annotation 包下創(chuàng)建一個(gè)名為 AnnotationTest 的測(cè)試類,如下所示。
package com.mengma.aspectj.annotation; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.mengma.dao.CustomerDao; public class AnnotationTest { @Test public void test() { String xmlPath = "com/mengma/aspectj/xml/applicationContext.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext( xmlPath); // 從spring容器獲取實(shí)例 CustomerDao customerDao = (CustomerDao) applicationContext .getBean("customerDao"); // 執(zhí)行方法 customerDao.add(); } }
5. 運(yùn)行項(xiàng)目并查看結(jié)果
使用 JUnit 測(cè)試運(yùn)行 test() 方法,運(yùn)行成功后,控制臺(tái)的輸出結(jié)果如圖 3 所示。
圖 3 運(yùn)行結(jié)果
刪除 add() 方法中的“int i=1/0;”,重新運(yùn)行 test() 方法,此時(shí)控制臺(tái)的輸出結(jié)果如圖 4 所示。
圖 4 運(yùn)行結(jié)果
從圖 3 和圖 4 的輸出結(jié)果中可以看出,已成功使用 Annotation 的方式實(shí)現(xiàn)了 AOP 開發(fā)。與其他方式相比,基于 Annotation 方式實(shí)現(xiàn) AOP 的效果是最方便的方式,所以實(shí)際開發(fā)中推薦使用注解的方式。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
springboot 事件監(jiān)聽的實(shí)現(xiàn)方法
這篇文章主要介紹了springboot 事件監(jiān)聽的實(shí)現(xiàn)方法,并詳細(xì)的介紹了四種監(jiān)聽方式,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-04-04java背包問題動(dòng)態(tài)規(guī)劃算法分析
這篇文章主要介紹了java背包問題動(dòng)態(tài)規(guī)劃算法分析,想了解算法的同學(xué)一定要看一下2021-04-04Java實(shí)現(xiàn)微信公眾號(hào)獲取臨時(shí)二維碼功能示例
這篇文章主要介紹了Java實(shí)現(xiàn)微信公眾號(hào)獲取臨時(shí)二維碼功能,結(jié)合實(shí)例形式分析了java調(diào)用微信公眾號(hào)接口實(shí)現(xiàn)臨時(shí)二維碼生成功能相關(guān)操作技巧,需要的朋友可以參考下2019-10-10SpringCloud?Feign請(qǐng)求頭刪除修改的操作代碼
這篇文章主要介紹了SpringCloud?Feign請(qǐng)求頭刪除修改,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03java用字節(jié)數(shù)組解決FileInputStream讀取漢字出現(xiàn)亂碼問題
這篇文章主要介紹了java用字節(jié)數(shù)組解決FileInputStream讀取漢字出現(xiàn)亂碼問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05java實(shí)現(xiàn)掃雷游戲控制臺(tái)版
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)掃雷游戲控制臺(tái)版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04SpringBoot實(shí)現(xiàn)熱部署Community的示例代碼
本文主要介紹了SpringBoot實(shí)現(xiàn)熱部署Community的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06