Spring??AOP的兩種使用方法
前言
記錄下 Spring AOP 的兩種使用方式,不談概念,只記錄兩種方式的使用例子
- 注解方式
- xml 配置方式
1 注解方式
1.1 聲明目標(biāo)類 UserDao 類
@Repository("userDao") public class UserDao { public void addUser() { System.out.println("?? 攔截的方法 addUser 開始執(zhí)行"); } }
1.2 聲明切面 AnnotationAspect 類
@Aspect @Component public class AnnotationAspect { // 定義切入點(diǎn)表達(dá)式, 使用一個(gè)返回值為 void、方法體為空的方法來命名切入點(diǎn) @Pointcut("execution(* com.fairy.springmvc.aspectj.annotation.*.*(..))") private void customPointCut(){} // 前置通知 @Before("customPointCut()") public void myBefore(JoinPoint joinPoint){ System.out.print("前置通知:模擬執(zhí)行權(quán)限檢查..,"); System.out.print("目標(biāo)類是:" + joinPoint.getTarget()); System.out.println(",被植入增強(qiáng)處理的目標(biāo)方法為:" + joinPoint.getSignature().getName()); } // 后置通知 @AfterReturning(value="customPointCut()") public void myAfterReturning(JoinPoint joinPoint) { System.out.print("后置通知:模擬記錄日志..,"); System.out.println("被植入增強(qiáng)處理的目標(biāo)方法為:" + joinPoint.getSignature().getName()); } /** * 環(huán)繞通知 * ProceedingJoinPoint 是 JoinPoint的子接口,表示可執(zhí)行目標(biāo)方法 * 1.必須是 Object 類型的返回值 * 2.必須接收一個(gè)參數(shù),類型為 ProceedingJoinPoint * 3.必須 throws Throwable */ @Around("customPointCut()") public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{ // 開始 System.out.println("環(huán)繞開始:執(zhí)行目標(biāo)方法之前,模擬開啟事務(wù)..,"); // 執(zhí)行當(dāng)前目標(biāo)方法 Object obj = proceedingJoinPoint.proceed(); // 結(jié)束 System.out.println("環(huán)繞結(jié)束:執(zhí)行目標(biāo)方法之后,模擬關(guān)閉事務(wù)..,"); return obj; } /** * 異常通知處理 * @param joinPoint * @param e */ @AfterThrowing(value="customPointCut()",throwing="e") public void myAfterThrowing(JoinPoint joinPoint, Throwable e){ System.out.println("異常通知:出錯(cuò)了" + e.getMessage()); } // 最終通知 @After("customPointCut()") public void myAfter(){ System.out.println("最終通知:模擬方法結(jié)束后釋放資源.."); } }
1.3 聲明配置
開啟@AspectJ
的注解配置方式,有兩種方式
1 在 xml
文件,添加以下配置:
<!-- 啟動(dòng)基于注解的聲明式 AspectJ 支持 --> <aop:aspectj-autoproxy />
2 使用了 Java
代碼風(fēng)格的配置,則需使用 EnableAspectJAutoProxy
注解
示例如下
@Configuration @EnableAspectJAutoProxy @ComponentScan("com.fairy.springmvc") public class ApplicationConfig { .... }
1.4 測(cè)試用例
public class TestCase { @Test public void testAnnotation() throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "spring-test.xml"); // 從容器中獲得內(nèi)容 UserDao userDao= (UserDao) applicationContext.getBean("userDao"); // 執(zhí)行方法 userDao.addUser(); } }
運(yùn)行結(jié)果如下:
環(huán)繞開始:執(zhí)行目標(biāo)方法之前,模擬開啟事務(wù)..,
前置通知:模擬執(zhí)行權(quán)限檢查..,
目標(biāo)類是:com.fairy.springmvc.aspectj.annotation.UserDao@4a699efa,
被植入增強(qiáng)處理的目標(biāo)方法為:addUser
?? 攔截的方法 addUser 開始執(zhí)行
后置通知:模擬記錄日志..,被植入增強(qiáng)處理的目標(biāo)方法為:addUser
最終通知:模擬方法結(jié)束后釋放資源..
環(huán)繞結(jié)束:執(zhí)行目標(biāo)方法之后,模擬關(guān)閉事務(wù)..,
通過輸出結(jié)果看出,符合預(yù)期。
2 XML 配置方式
2.1 聲明目標(biāo)類 CompanyDao
@Repository("companyDao") public class CompanyDao { public void addCompany() { System.out.println("?? 真正的業(yè)務(wù)處理:add company ??"); } public void exception() throws Exception { throw new Exception("業(yè)務(wù)異常了"); } }
2.2 聲明切面攔截類 XmlAspect
@Component("xmlAspectConfig") public class XmlAspect { public void printUnderscore() { System.out.println("------------------------------------------------"); } /** * 在核心業(yè)務(wù)執(zhí)行前執(zhí)行,不能阻止核心業(yè)務(wù)的調(diào)用 * @param joinPoint */ public void beforeAdvice(JoinPoint joinPoint) { printUnderscore(); System.out.println("1?? 通知:beforeAdvice 執(zhí)行開始"); System.out.println(" 執(zhí)行核心業(yè)務(wù)邏輯前,可以做一些前置的安全性的檢測(cè)等"); System.out.println(" 通知:beforeAdvice 執(zhí)行結(jié)束"); printUnderscore(); } /** * 核心業(yè)務(wù)退出后,不管是正常結(jié)束還是異常退出,均執(zhí)行此通知 * @param joinPoint */ public void afterAdvice(JoinPoint joinPoint) { printUnderscore(); System.out.println("4?? 通知:afterAdvice 執(zhí)行開始"); System.out.println(" 此處可以對(duì)返回值做進(jìn)一步的處理"); System.out.println(" 通知:afterAdvice 執(zhí)行結(jié)束"); } /** * 核心業(yè)務(wù)調(diào)用正常退出后,不管是否有返回值,只要是正常退出,都會(huì)執(zhí)行此通知 * @param joinPoint */ public void afterReturningAdvice(JoinPoint joinPoint) { printUnderscore(); System.out.println("2?? 通知:afterReturningAdvice 執(zhí)行開始"); System.out.println(" 此處可以對(duì)返回值做進(jìn)一步處理"); System.out.println(" 通知:afterReturningAdvice 執(zhí)行結(jié)束"); } /** * 核心業(yè)務(wù)邏輯調(diào)用異常退出后,執(zhí)行此通知,處理錯(cuò)誤信息 * @param e */ public void afterThrowingAdvice(Exception e) { printUnderscore(); System.out.println("3?? 通知:afterThrowingAdvice 執(zhí)行開始"); System.out.println(" 錯(cuò)誤信息:" + e.getMessage()); System.out.println(" 此處意味著,在核心業(yè)務(wù)邏輯出錯(cuò)時(shí),捕獲異常,并可以做一些日志記錄相關(guān)的操作"); } /** * 手動(dòng)控制調(diào)用核心業(yè)務(wù)邏輯,以及調(diào)用前和調(diào)用后的處理 * @param pjp */ public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable { // 開始 System.out.println("5?? 環(huán)繞開始:執(zhí)行目標(biāo)方法之前"); System.out.println(" 此處可以做類似于 Before Advice 的事情"); // 調(diào)用核心邏輯,執(zhí)行當(dāng)前目標(biāo)方法 Object obj = pjp.proceed(); // 打印下劃線 printUnderscore(); // 結(jié)束 System.out.println(" 此處可以做類似于 After Advice 的事情"); System.out.println("5?? 環(huán)繞結(jié)束:執(zhí)行目標(biāo)方法之后"); return obj; } }
2.3 聲明 XML 配置
<!-- 基于 XML 文件的配置進(jìn)行聲明,注意和 aop:aspectj-autoproxy 的區(qū)別 --> <aop:config proxy-target-class="true"> <!-- 基于 aspect 配置一個(gè)完整的切面 --> <aop:aspect id="aspectXmlConfigExample" ref="xmlAspectConfig"> <!-- 切點(diǎn)配置,可以配置多個(gè)切點(diǎn) --> <aop:pointcut id="xmlPointCut" expression="execution(* com.fairy.springmvc.aspectj.xml.CompanyDao.*(..))"/> <aop:after-returning method="afterReturningAdvice" pointcut-ref="xmlPointCut" /> <aop:after-throwing method="afterThrowingAdvice" pointcut-ref="xmlPointCut" throwing="e"/> <aop:after method="afterAdvice" pointcut-ref="xmlPointCut" /> <aop:around method="aroundAdvice" pointcut-ref="xmlPointCut" /> <aop:before method="beforeAdvice" pointcut-ref="xmlPointCut" /> </aop:aspect> </aop:config>
注意:
值得注意的是
around
與before
和after
的執(zhí)行順序。3
者的執(zhí)行順序取決于在xml
中的配置順序。
2.3 測(cè)試用例
public class TestCase { @Test public void testAnnotation() throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "spring-test.xml"); CompanyDao companyDao = (CompanyDao) applicationContext.getBean("companyDao"); companyDao.addCompany(); // companyDao.exception(); } }
輸出結(jié)果如下:
-------------------------------
5?? 環(huán)繞開始:執(zhí)行目標(biāo)方法之前
此處可以做類似于 Before Advice 的事情
------------------------------------------------
1?? 通知:beforeAdvice 執(zhí)行開始
執(zhí)行核心業(yè)務(wù)邏輯前,可以做一些前置的安全性的檢測(cè)等
通知:beforeAdvice 執(zhí)行結(jié)束
------------------------------------------------
?? 真正的業(yè)務(wù)處理:add company ??
------------------------------------------------
2?? 通知:afterReturningAdvice 執(zhí)行開始
此處可以對(duì)返回值做進(jìn)一步處理
通知:afterReturningAdvice 執(zhí)行結(jié)束
------------------------------------------------
4?? 通知:afterAdvice 執(zhí)行開始
此處可以對(duì)返回值做進(jìn)一步的處理
通知:afterAdvice 執(zhí)行結(jié)束
------------------------------------------------
此處可以做類似于 After Advice 的事情
5?? 環(huán)繞結(jié)束:執(zhí)行目標(biāo)方法之后
結(jié)果符合預(yù)期。
到此這篇關(guān)于Spring AOP 的兩種使用方法的文章就介紹到這了,更多相關(guān)Spring AOP 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解spring boot容器加載完后執(zhí)行特定操作
這篇文章主要介紹了詳解spring boot容器加載完后執(zhí)行特定操作,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01Hibernate框架數(shù)據(jù)分頁(yè)技術(shù)實(shí)例分析
這篇文章主要介紹了Hibernate框架數(shù)據(jù)分頁(yè)技術(shù),結(jié)合實(shí)例形式分析了Hibernate框架實(shí)現(xiàn)數(shù)據(jù)分頁(yè)的原理,步驟與相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-03-03使用注解@Validated效驗(yàn)VO參數(shù)是否合規(guī)
這篇文章主要為大家介紹了使用注解@Validated效驗(yàn)VO參數(shù)是否合規(guī)過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05解決Eclipse配置Tomcat出現(xiàn)Cannot create a server using the selected
這篇文章主要介紹了解決Eclipse配置Tomcat出現(xiàn)Cannot create a server using the selected type錯(cuò)誤的相關(guān)資料,需要的朋友可以參考下2017-02-02Java使用GZIP壓縮導(dǎo)致HTTP請(qǐng)求返回亂碼問題解決
這篇文章主要為大家介紹了Java壓縮GZIP導(dǎo)致HTTP請(qǐng)求返回亂碼問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06