Spring??AOP的兩種使用方法
前言
記錄下 Spring AOP 的兩種使用方式,不談概念,只記錄兩種方式的使用例子
- 注解方式
- xml 配置方式
1 注解方式
1.1 聲明目標(biāo)類(lèi) UserDao 類(lèi)
@Repository("userDao")
public class UserDao {
public void addUser() {
System.out.println("?? 攔截的方法 addUser 開(kāi)始執(zhí)行");
}
}1.2 聲明切面 AnnotationAspect 類(lèi)
@Aspect
@Component
public class AnnotationAspect {
// 定義切入點(diǎn)表達(dá)式, 使用一個(gè)返回值為 void、方法體為空的方法來(lái)命名切入點(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)類(lèi)是:" + 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 類(lèi)型的返回值
* 2.必須接收一個(gè)參數(shù),類(lèi)型為 ProceedingJoinPoint
* 3.必須 throws Throwable
*/
@Around("customPointCut()")
public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
// 開(kāi)始
System.out.println("環(huán)繞開(kāi)始:執(zhí)行目標(biāo)方法之前,模擬開(kāi)啟事務(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 聲明配置
開(kāi)啟@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)繞開(kāi)始:執(zhí)行目標(biāo)方法之前,模擬開(kāi)啟事務(wù)..,
前置通知:模擬執(zhí)行權(quán)限檢查..,
目標(biāo)類(lèi)是:com.fairy.springmvc.aspectj.annotation.UserDao@4a699efa,
被植入增強(qiáng)處理的目標(biāo)方法為:addUser
?? 攔截的方法 addUser 開(kāi)始執(zhí)行
后置通知:模擬記錄日志..,被植入增強(qiáng)處理的目標(biāo)方法為:addUser
最終通知:模擬方法結(jié)束后釋放資源..
環(huán)繞結(jié)束:執(zhí)行目標(biāo)方法之后,模擬關(guān)閉事務(wù)..,
通過(guò)輸出結(jié)果看出,符合預(yù)期。
2 XML 配置方式
2.1 聲明目標(biāo)類(lèi) 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 聲明切面攔截類(lèi) 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í)行開(kāi)始");
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í)行開(kāi)始");
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í)行開(kāi)始");
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í)行開(kāi)始");
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 {
// 開(kāi)始
System.out.println("5?? 環(huán)繞開(kāi)始:執(zhí)行目標(biāo)方法之前");
System.out.println(" 此處可以做類(lèi)似于 Before Advice 的事情");
// 調(diào)用核心邏輯,執(zhí)行當(dāng)前目標(biāo)方法
Object obj = pjp.proceed();
// 打印下劃線
printUnderscore();
// 結(jié)束
System.out.println(" 此處可以做類(lèi)似于 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)繞開(kāi)始:執(zhí)行目標(biāo)方法之前
此處可以做類(lèi)似于 Before Advice 的事情
------------------------------------------------
1?? 通知:beforeAdvice 執(zhí)行開(kāi)始
執(zhí)行核心業(yè)務(wù)邏輯前,可以做一些前置的安全性的檢測(cè)等
通知:beforeAdvice 執(zhí)行結(jié)束
------------------------------------------------
?? 真正的業(yè)務(wù)處理:add company ??
------------------------------------------------
2?? 通知:afterReturningAdvice 執(zhí)行開(kāi)始
此處可以對(duì)返回值做進(jìn)一步處理
通知:afterReturningAdvice 執(zhí)行結(jié)束
------------------------------------------------
4?? 通知:afterAdvice 執(zhí)行開(kāi)始
此處可以對(duì)返回值做進(jìn)一步的處理
通知:afterAdvice 執(zhí)行結(jié)束
------------------------------------------------
此處可以做類(lèi)似于 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)文章
Java創(chuàng)建和啟動(dòng)線程的兩種方式實(shí)例分析
這篇文章主要介紹了Java創(chuàng)建和啟動(dòng)線程的兩種方式,結(jié)合實(shí)例形式分析了java多線程創(chuàng)建、使用相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2019-09-09
Java編程實(shí)現(xiàn)游戲中的簡(jiǎn)單碰撞檢測(cè)功能示例
這篇文章主要介紹了Java編程中的簡(jiǎn)單碰撞檢測(cè)功能,涉及java針對(duì)坐標(biāo)點(diǎn)的相關(guān)數(shù)學(xué)運(yùn)算操作技巧,需要的朋友可以參考下2017-10-10
Mybatis Plus 字段為空值時(shí)執(zhí)行更新方法未更新解決方案
這篇文章主要介紹了Mybatis Plus 字段為空值時(shí)執(zhí)行更新方法未更新解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
利用Java如何獲取Mybatis動(dòng)態(tài)生成的sql接口實(shí)現(xiàn)
MyBatis 的強(qiáng)大特性之一便是它的動(dòng)態(tài)SQL,下面這篇文章主要給大家介紹了關(guān)于利用Java如何獲取Mybatis動(dòng)態(tài)生成的sql接口實(shí)現(xiàn)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-01-01
Spring?Native打包本地鏡像的操作方法(無(wú)需通過(guò)Graal的maven插件buildtools)
這篇文章主要介紹了Spring?Native打包本地鏡像,無(wú)需通過(guò)Graal的maven插件buildtools,本文探索一下,如果不通過(guò)這個(gè)插件來(lái)生成鏡像,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02
java調(diào)用淘寶api聯(lián)網(wǎng)查詢ip歸屬地
java聯(lián)網(wǎng)查詢IP歸屬地,原理是根據(jù)淘寶提供的service查詢IP的歸屬地并且解析http請(qǐng)求返回的json串2014-03-03
深入探討Java 中的 Object 類(lèi)詳解(一切類(lèi)的根基)
本文詳細(xì)介紹了Java中的Object類(lèi),作為所有類(lèi)的根類(lèi),其重要性不言而喻,文章涵蓋了Object類(lèi)的主要方法,如toString()、equals()、hashCode()等,本文深入探討 Object 類(lèi)的作用、常用方法以及如何在實(shí)際開(kāi)發(fā)中利用這些方法,感興趣的朋友一起看看吧2025-01-01
利用Springboot實(shí)現(xiàn)Jwt認(rèn)證的示例代碼
這篇文章主要介紹了利用Springboot實(shí)現(xiàn)Jwt認(rèn)證的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
詳解SpringBoot是如何整合SpringDataRedis的?
今天給大家?guī)?lái)的是關(guān)于Java的相關(guān)知識(shí),文章圍繞著SpringBoot是如何整合SpringDataRedis展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06

