Spring??AOP的兩種使用方法
前言
記錄下 Spring AOP 的兩種使用方式,不談概念,只記錄兩種方式的使用例子
- 注解方式
- xml 配置方式
1 注解方式
1.1 聲明目標類 UserDao 類
@Repository("userDao")
public class UserDao {
public void addUser() {
System.out.println("?? 攔截的方法 addUser 開始執(zhí)行");
}
}1.2 聲明切面 AnnotationAspect 類
@Aspect
@Component
public class AnnotationAspect {
// 定義切入點表達式, 使用一個返回值為 void、方法體為空的方法來命名切入點
@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("目標類是:" + joinPoint.getTarget());
System.out.println(",被植入增強處理的目標方法為:" + joinPoint.getSignature().getName());
}
// 后置通知
@AfterReturning(value="customPointCut()")
public void myAfterReturning(JoinPoint joinPoint) {
System.out.print("后置通知:模擬記錄日志..,");
System.out.println("被植入增強處理的目標方法為:" + joinPoint.getSignature().getName());
}
/**
* 環(huán)繞通知
* ProceedingJoinPoint 是 JoinPoint的子接口,表示可執(zhí)行目標方法
* 1.必須是 Object 類型的返回值
* 2.必須接收一個參數(shù),類型為 ProceedingJoinPoint
* 3.必須 throws Throwable
*/
@Around("customPointCut()")
public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
// 開始
System.out.println("環(huán)繞開始:執(zhí)行目標方法之前,模擬開啟事務..,");
// 執(zhí)行當前目標方法
Object obj = proceedingJoinPoint.proceed();
// 結(jié)束
System.out.println("環(huán)繞結(jié)束:執(zhí)行目標方法之后,模擬關(guān)閉事務..,");
return obj;
}
/**
* 異常通知處理
* @param joinPoint
* @param e
*/
@AfterThrowing(value="customPointCut()",throwing="e")
public void myAfterThrowing(JoinPoint joinPoint, Throwable e){
System.out.println("異常通知:出錯了" + e.getMessage());
}
// 最終通知
@After("customPointCut()")
public void myAfter(){
System.out.println("最終通知:模擬方法結(jié)束后釋放資源..");
}
}1.3 聲明配置
開啟@AspectJ的注解配置方式,有兩種方式
1 在 xml 文件,添加以下配置:
<!-- 啟動基于注解的聲明式 AspectJ 支持 --> <aop:aspectj-autoproxy />
2 使用了 Java 代碼風格的配置,則需使用 EnableAspectJAutoProxy 注解
示例如下
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.fairy.springmvc")
public class ApplicationConfig {
....
}1.4 測試用例
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();
}
}運行結(jié)果如下:
環(huán)繞開始:執(zhí)行目標方法之前,模擬開啟事務..,
前置通知:模擬執(zhí)行權(quán)限檢查..,
目標類是:com.fairy.springmvc.aspectj.annotation.UserDao@4a699efa,
被植入增強處理的目標方法為:addUser
?? 攔截的方法 addUser 開始執(zhí)行
后置通知:模擬記錄日志..,被植入增強處理的目標方法為:addUser
最終通知:模擬方法結(jié)束后釋放資源..
環(huán)繞結(jié)束:執(zhí)行目標方法之后,模擬關(guān)閉事務..,
通過輸出結(jié)果看出,符合預期。
2 XML 配置方式
2.1 聲明目標類 CompanyDao
@Repository("companyDao")
public class CompanyDao {
public void addCompany() {
System.out.println("?? 真正的業(yè)務處理:add company ??");
}
public void exception() throws Exception {
throw new Exception("業(yè)務異常了");
}
}2.2 聲明切面攔截類 XmlAspect
@Component("xmlAspectConfig")
public class XmlAspect {
public void printUnderscore() {
System.out.println("------------------------------------------------");
}
/**
* 在核心業(yè)務執(zhí)行前執(zhí)行,不能阻止核心業(yè)務的調(diào)用
* @param joinPoint
*/
public void beforeAdvice(JoinPoint joinPoint) {
printUnderscore();
System.out.println("1?? 通知:beforeAdvice 執(zhí)行開始");
System.out.println(" 執(zhí)行核心業(yè)務邏輯前,可以做一些前置的安全性的檢測等");
System.out.println(" 通知:beforeAdvice 執(zhí)行結(jié)束");
printUnderscore();
}
/**
* 核心業(yè)務退出后,不管是正常結(jié)束還是異常退出,均執(zhí)行此通知
* @param joinPoint
*/
public void afterAdvice(JoinPoint joinPoint) {
printUnderscore();
System.out.println("4?? 通知:afterAdvice 執(zhí)行開始");
System.out.println(" 此處可以對返回值做進一步的處理");
System.out.println(" 通知:afterAdvice 執(zhí)行結(jié)束");
}
/**
* 核心業(yè)務調(diào)用正常退出后,不管是否有返回值,只要是正常退出,都會執(zhí)行此通知
* @param joinPoint
*/
public void afterReturningAdvice(JoinPoint joinPoint) {
printUnderscore();
System.out.println("2?? 通知:afterReturningAdvice 執(zhí)行開始");
System.out.println(" 此處可以對返回值做進一步處理");
System.out.println(" 通知:afterReturningAdvice 執(zhí)行結(jié)束");
}
/**
* 核心業(yè)務邏輯調(diào)用異常退出后,執(zhí)行此通知,處理錯誤信息
* @param e
*/
public void afterThrowingAdvice(Exception e) {
printUnderscore();
System.out.println("3?? 通知:afterThrowingAdvice 執(zhí)行開始");
System.out.println(" 錯誤信息:" + e.getMessage());
System.out.println(" 此處意味著,在核心業(yè)務邏輯出錯時,捕獲異常,并可以做一些日志記錄相關(guān)的操作");
}
/**
* 手動控制調(diào)用核心業(yè)務邏輯,以及調(diào)用前和調(diào)用后的處理
* @param pjp
*/
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
// 開始
System.out.println("5?? 環(huán)繞開始:執(zhí)行目標方法之前");
System.out.println(" 此處可以做類似于 Before Advice 的事情");
// 調(diào)用核心邏輯,執(zhí)行當前目標方法
Object obj = pjp.proceed();
// 打印下劃線
printUnderscore();
// 結(jié)束
System.out.println(" 此處可以做類似于 After Advice 的事情");
System.out.println("5?? 環(huán)繞結(jié)束:執(zhí)行目標方法之后");
return obj;
}
}2.3 聲明 XML 配置
<!-- 基于 XML 文件的配置進行聲明,注意和 aop:aspectj-autoproxy 的區(qū)別 -->
<aop:config proxy-target-class="true">
<!-- 基于 aspect 配置一個完整的切面 -->
<aop:aspect id="aspectXmlConfigExample" ref="xmlAspectConfig">
<!-- 切點配置,可以配置多個切點 -->
<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 測試用例
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í)行目標方法之前
此處可以做類似于 Before Advice 的事情
------------------------------------------------
1?? 通知:beforeAdvice 執(zhí)行開始
執(zhí)行核心業(yè)務邏輯前,可以做一些前置的安全性的檢測等
通知:beforeAdvice 執(zhí)行結(jié)束
------------------------------------------------
?? 真正的業(yè)務處理:add company ??
------------------------------------------------
2?? 通知:afterReturningAdvice 執(zhí)行開始
此處可以對返回值做進一步處理
通知:afterReturningAdvice 執(zhí)行結(jié)束
------------------------------------------------
4?? 通知:afterAdvice 執(zhí)行開始
此處可以對返回值做進一步的處理
通知:afterAdvice 執(zhí)行結(jié)束
------------------------------------------------
此處可以做類似于 After Advice 的事情
5?? 環(huán)繞結(jié)束:執(zhí)行目標方法之后
結(jié)果符合預期。
到此這篇關(guān)于Spring AOP 的兩種使用方法的文章就介紹到這了,更多相關(guān)Spring AOP 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis Plus 字段為空值時執(zhí)行更新方法未更新解決方案
這篇文章主要介紹了Mybatis Plus 字段為空值時執(zhí)行更新方法未更新解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-09-09
利用Java如何獲取Mybatis動態(tài)生成的sql接口實現(xiàn)
MyBatis 的強大特性之一便是它的動態(tài)SQL,下面這篇文章主要給大家介紹了關(guān)于利用Java如何獲取Mybatis動態(tài)生成的sql接口實現(xiàn)的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-01-01
Spring?Native打包本地鏡像的操作方法(無需通過Graal的maven插件buildtools)
這篇文章主要介紹了Spring?Native打包本地鏡像,無需通過Graal的maven插件buildtools,本文探索一下,如果不通過這個插件來生成鏡像,結(jié)合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2023-02-02
java調(diào)用淘寶api聯(lián)網(wǎng)查詢ip歸屬地
java聯(lián)網(wǎng)查詢IP歸屬地,原理是根據(jù)淘寶提供的service查詢IP的歸屬地并且解析http請求返回的json串2014-03-03
深入探討Java 中的 Object 類詳解(一切類的根基)
本文詳細介紹了Java中的Object類,作為所有類的根類,其重要性不言而喻,文章涵蓋了Object類的主要方法,如toString()、equals()、hashCode()等,本文深入探討 Object 類的作用、常用方法以及如何在實際開發(fā)中利用這些方法,感興趣的朋友一起看看吧2025-01-01
利用Springboot實現(xiàn)Jwt認證的示例代碼
這篇文章主要介紹了利用Springboot實現(xiàn)Jwt認證的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-12-12
詳解SpringBoot是如何整合SpringDataRedis的?
今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識,文章圍繞著SpringBoot是如何整合SpringDataRedis展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下2021-06-06

