網(wǎng)站首頁 編程語言 正文
AOP切面編程
- 通知類型
- 表達(dá)式
- 重用表達(dá)式
- 切面優(yōu)先級
- 使用注解開發(fā),加上注解實(shí)現(xiàn)某些功能
簡介
- 動(dòng)態(tài)代理分為JDK動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理
- 當(dāng)目標(biāo)類有接口的情況使用JDK動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理,沒有接口時(shí)只能使用cglib動(dòng)態(tài)代理
- JDK動(dòng)態(tài)代理動(dòng)態(tài)生成的代理類會(huì)在com.sun.proxy包下,類名為$proxy1,和目標(biāo)類實(shí)現(xiàn)相同的接口
- cglib動(dòng)態(tài)代理動(dòng)態(tài)生成的代理類會(huì)和目標(biāo)在在相同的包下,會(huì)繼承目標(biāo)類
- 動(dòng)態(tài)代理(InvocationHandler):JDK原生的實(shí)現(xiàn)方式,需要被代理的目標(biāo)類必須實(shí)現(xiàn)接口。因?yàn)檫@個(gè)技術(shù)要求代理對象和目標(biāo)對象實(shí)現(xiàn)同樣的接口(兄弟兩個(gè)拜把子模式)。
- cglib:通過繼承被代理的目標(biāo)類(認(rèn)干爹模式)實(shí)現(xiàn)代理,所以不需要目標(biāo)類實(shí)現(xiàn)接口。
- AspectJ:是AOP思想的一種實(shí)現(xiàn)。本質(zhì)上是靜態(tài)代理,將代理邏輯“織入”被代理的目標(biāo)類編譯得到的字節(jié)碼文件,所以最終效果是動(dòng)態(tài)的。weaver就是織入器。Spring只是借用了AspectJ中的注解。
依賴
<!--spring context依賴-->
<!--當(dāng)你引入Spring Context依賴之后,表示將Spring的基礎(chǔ)依賴引入了-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.2</version>
</dependency>
<!--spring aop依賴-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>6.0.2</version>
</dependency>
<!--spring aspects依賴-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>6.0.2</version>
</dependency>
注解說明
-
@Aspect
表示這個(gè)類是一個(gè)切面類 -
@Component
注解保證這個(gè)切面類能夠放入IOC容器
簡單使用
幾種通知類型
- 前置通知
@Before()
- 環(huán)繞通知
@Around()
- 返回通知
@AfterReturning()
- 異常通知
@AfterThrowing()
- 后置通知
@After()
表達(dá)式介紹
切入點(diǎn)表達(dá)式
在方法中可以傳入?yún)?shù)public void afterMethod(JoinPoint joinPoint)
,類型為JoinPoint
-
獲取連接點(diǎn)的簽名信息
-
String methodName = joinPoint.getSignature().getName()
-
-
獲取目標(biāo)方法的返回值
-
其中表達(dá)式中
returning
后面參數(shù)result
要與public void afterReturningMethod(JoinPoint joinPoint, Object result)
傳入?yún)?shù)名稱一樣,類型可以不一樣但是名稱要一樣。 -
@AfterReturning(value = "execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..))", returning = "result") public void afterReturningMethod(JoinPoint joinPoint, Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println("Logger-->返回通知,方法名:"+methodName+",結(jié)果:"+result); }
-
-
獲取目標(biāo)方法的異常
-
在表達(dá)式中加入
throwing = "ex"
,和上面一樣,傳入?yún)?shù)名稱要一直,也要是ex
,如:Throwable ex
-
@AfterThrowing(value = "execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..))", throwing = "ex") public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex){ String methodName = joinPoint.getSignature().getName(); System.out.println("Logger-->異常通知,方法名:"+methodName+",異常:"+ex); }
-
切入點(diǎn)表達(dá)式使用
前置通知
@Aspect// 表示這個(gè)類是一個(gè)切面類
@Component// 注解保證這個(gè)切面類能夠放入IOC容器
public class LogAspect {
// 設(shè)置切入點(diǎn)和通知類型
@Before(value = "execution(public int com.example.aop.annoaop.CalculatorImpl.*(..))")
public void beforeMethod(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
System.out.println("Logger-->前置通知" + "參數(shù):" + args[0] + "," + args[1]);
}
}
后置通知
@Aspect// 表示這個(gè)類是一個(gè)切面類
@Component// 注解保證這個(gè)切面類能夠放入IOC容器
public class LogAspect {
@After(value = "execution(public int com.example.aop.annoaop.CalculatorImpl.*(..))")
public void afterMethod(JoinPoint joinPoint) {
String name = joinPoint.getSignature().getName();// 方法名
System.out.println("Logger-->后置通知,方法名:" + name);
}
}
返回通知
@Aspect// 表示這個(gè)類是一個(gè)切面類
@Component// 注解保證這個(gè)切面類能夠放入IOC容器
public class LogAspect {
@AfterReturning(value = "execution(public int com.example.aop.annoaop.CalculatorImpl.*(..))", returning = "result")
public void afterReturn(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println("Logger-->返回通知,方法名:" + methodName + ",結(jié)果:" + result);
}
}
異常通知
@Aspect// 表示這個(gè)類是一個(gè)切面類
@Component// 注解保證這個(gè)切面類能夠放入IOC容器
public class LogAspect {
@AfterThrowing(value = "execution(public int com.example.aop.annoaop.CalculatorImpl.*(..))", throwing = "ex")
public void afterThrowingMethod(JoinPoint joinPoint, Exception ex) {
String methodName = joinPoint.getSignature().getName();
System.out.println("Logger-->異常通知,方法名:" + methodName + ",異常:" + ex);
}
}
環(huán)繞通知
@Aspect// 表示這個(gè)類是一個(gè)切面類
@Component// 注解保證這個(gè)切面類能夠放入IOC容器
public class LogAspect {
@Around(value = "execution(public int com.example.aop.annoaop.CalculatorImpl.*(..))")
public Object aroundMethod(ProceedingJoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
String args = Arrays.toString(joinPoint.getArgs());
Object result = null;
try {
System.out.println("環(huán)繞通知-->目標(biāo)對象方法執(zhí)行之前");
// 目標(biāo)對象(連接點(diǎn))方法的執(zhí)行
result = joinPoint.proceed();
System.out.println("環(huán)繞通知-->目標(biāo)對象方法返回值之后");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("環(huán)繞通知-->目標(biāo)對象方法出現(xiàn)異常時(shí)");
} finally {
System.out.println("環(huán)繞通知-->目標(biāo)對象方法執(zhí)行完畢");
}
return result;
}
}
重用切入點(diǎn)表達(dá)式
申明表達(dá)式
@Pointcut("execution(* com.atguigu.aop.annotation.*.*(..))")
public void pointCut(){}
在方法中使用
@Before("pointCut()")
public void beforeMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
String args = Arrays.toString(joinPoint.getArgs());
System.out.println("Logger-->前置通知,方法名:"+methodName+",參數(shù):"+args);
}
在不同切面中使用
@Before("com.atguigu.aop.CommonPointCut.pointCut()")
public void beforeMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
String args = Arrays.toString(joinPoint.getArgs());
System.out.println("Logger-->前置通知,方法名:"+methodName+",參數(shù):"+args);
}
切面的優(yōu)先級
相同目標(biāo)方法上同時(shí)存在多個(gè)切面時(shí),切面的優(yōu)先級控制切面的內(nèi)外嵌套順序。
- 優(yōu)先級高的切面:外面
- 優(yōu)先級低的切面:里面
使用@Order注解可以控制切面的優(yōu)先級:
- @Order(較小的數(shù)):優(yōu)先級高
- @Order(較大的數(shù)):優(yōu)先級低
將@Order注解放在切面類上而不是方法上!!!
- 優(yōu)先級低的
@Aspect// 表示這個(gè)類是一個(gè)切面類
@Component// 注解保證這個(gè)切面類能夠放入IOC容器
@Order(4)
public class LogAspect {
@After(value = "pointcut()")
public void afterMethod2(JoinPoint joinPoint) {
String name = joinPoint.getSignature().getName();// 方法名
System.out.println("Logger-->后置通知 111111,方法名:" + name);
}
}
- 優(yōu)先級高的
@Aspect// 表示這個(gè)類是一個(gè)切面類
@Component// 注解保證這個(gè)切面類能夠放入IOC容器
@Order(1)
public class NewLogAspect {
@After(value = "com.example.aop.annoaop.LogAspect.pointcut()")
public void afterMethod(JoinPoint joinPoint) {
String name = joinPoint.getSignature().getName();// 方法名
System.out.println("Logger-->后置通知 444444,方法名:" + name);
}
}
效果
原先交換順序后
沒有交換順序前
注解使用
使用AOP在方法或者接口上寫上某些注解,完成特定方法。
實(shí)現(xiàn)思路
- 創(chuàng)建
@interface
- 和上面一樣要寫
Aspect
,并且要被spring
管理 - 在方法或者接口上加上
@interface
注解
實(shí)現(xiàn)示例
- 創(chuàng)建
@interface
并命名為BunnyLog
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
// 加上這個(gè)注解打印當(dāng)前時(shí)間
public @interface BunnyLog {
}
-
使用AOP切面,需要注意的是:
-
如果只是單純的加上注解,不考慮指定類或者類中方法,完成某些功能,要修改下面切入點(diǎn)
-
@Pointcut(value = "@annotation(com.example.aop.annoaop.BunnyLog)") public void bunnyPointcut() { }
-
-
如果想指定某些類或者某些方法下的
-
@Pointcut("execution(* com.example.aop.annoaop.*.*(..)) && @annotation(com.example.aop.annoaop.BunnyLog)") public void bunnyPointcut() { }
-
-
-
創(chuàng)建切面
@Aspect
@Component
public class BunnyAspect {
/**
* 切入點(diǎn),并且加上了 @BunnyLog注解
*/
@Pointcut(value = "execution(* com.example.aop.annoaop.*.*(..)) || @annotation(com.example.aop.annoaop.BunnyLog)")
public void bunnyPointcut() {
}
@Before("bunnyPointcut()")
public void before(JoinPoint joinPoint) {
String name = joinPoint.getSignature().getName();
System.out.println("------AOP前置通知生效,方法名稱------>" + name);
LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyy年MM月dd日 HH:mm:ss");
String format = localDateTime.format(timeFormatter);
System.out.println("BunnyAspect,現(xiàn)在時(shí)間====>" + format);
}
}
- 普通方法,需要在類上加上
@Component
被spring管理,之后再方法中加上注解@BunnyLog
@Component
public class BunnyTestImpl {
@BunnyLog
public void method() {
LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyy年MM月dd日 HH:mm:ss");
String format = localDateTime.format(timeFormatter);
System.out.println("測試方法,現(xiàn)在時(shí)間====>" + format);
}
}
- 創(chuàng)建一個(gè)測試類
public class TestBefore {
@Test
public void test1() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
BunnyTestImpl bean = context.getBean(BunnyTestImpl.class);
bean.method();
}
}
執(zhí)行結(jié)果:
r);
System.out.println(“測試方法,現(xiàn)在時(shí)間====>” + format);
}
}
- 創(chuàng)建一個(gè)測試類
```java
public class TestBefore {
@Test
public void test1() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
BunnyTestImpl bean = context.getBean(BunnyTestImpl.class);
bean.method();
}
}
執(zhí)行結(jié)果:
原文鏈接:https://blog.csdn.net/weixin_46533577/article/details/136605066
- 上一篇:沒有了
- 下一篇:沒有了
相關(guān)推薦
- 2022-09-24 教你創(chuàng)建一個(gè)帶診斷工具的.NET鏡像_C#教程
- 2022-04-15 python中對正則表達(dá)式re包的簡單引用方式_python
- 2022-08-07 Python算法練習(xí)之二分查找算法的實(shí)現(xiàn)_python
- 2022-05-22 vscode調(diào)試container中的程序的方法步驟_相關(guān)技巧
- 2022-11-13 Python中tqdm的使用和例子_python
- 2022-07-21 查看JVM系統(tǒng)參數(shù)的默認(rèn)值
- 2022-10-15 QT?UDP網(wǎng)絡(luò)編程實(shí)現(xiàn)簡單消息傳輸_C 語言
- 2022-04-12 Error: Rule can only have one resource source (pro
- 欄目分類
-
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支