Spring boot面向切面的编程
官方文档
https://docs.spring.io/spring-boot/reference/features/aop.html#page-title
aop默认的配置
aop默认的代理方式CGLib
spring.aop.proxy-target-class=true
启用JDK代理修改配置
To use JDK proxies instead, set configprop:spring.aop.proxy-target-class
to false
.
spring.aop.proxy-target-class=false
关于aop的开启配置
If AspectJ is on the classpath, Spring Boot's auto-configuration will automatically enable AspectJ auto proxy such that @EnableAspectJAutoProxy
is not required.
只要引入aspectjweaver就默认开启aop
项目准备
springboot
-
spring boot 3.3.3
-
Jdk17
添加依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.22</version>
</dependency>
添加依赖后自动启用AspectJ
更多官方文档:https://docs.spring.io/spring-framework/reference/core/aop/ataspectj.html
编写配置类
package com.demo.springbootaop.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Aspect
@Order(1)
@Component
public class MyAspect {
//切入点
@Pointcut("execution(* com.demo.springbootaop.controller.*.*(..))")
public void dsPointCut() {
}
/**
* 通知类型
* Around 环绕通知
* Before 前置通知
* AfterReturning 后置通知
* AfterThrowing 异常通知
* After 最终通知
*
*/
@Around("dsPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕通知开始。。。。 ");
Object proceed = point.proceed();
System.out.println("环绕通知结束。。。。 ");
return proceed;
}
}
当有两个切面在同一个配置类里面时执行顺序
package com.demo.springbootaop.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Aspect
@Order(1)
@Component
public class MyAspect {
//切入点
/**
* 如何匹配切入点
* execution(返回值类型 包名.类名.方法名(参数))
* 更多匹配类型参考官方文档:<a href="https://docs.spring.io/spring-framework/reference/core/aop/ataspectj/pointcuts.html">...</a>
*/
@Pointcut("execution(* com.demo.springbootaop.controller.*.*(..))")
public void dsPointCut() {
}
/**
* 根据注解切入
* "@Annotation(com.demo.springbootaop.annotation.MyAnnotation)"
*/
@Pointcut("(@within(org.springframework.web.bind.annotation.RestController))")
public void pcAnnotation() {
}
/**
* 通知类型
* Around 环绕通知
* Before 前置通知
* AfterReturning 后置通知
* AfterThrowing 异常通知
* After 最终通知
*
*/
@Around("pcAnnotation()")
public Object aroundRestController(ProceedingJoinPoint point) throws Throwable {
System.out.println("RestController环绕通知开始。。。。 ");
Object proceed = point.proceed();
System.out.println("RestController环绕通知结束。。。。 ");
return proceed;
}
@Around("dsPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕通知开始。。。。 ");
Object proceed = point.proceed();
System.out.println("环绕通知结束。。。。 ");
return proceed;
}
}
执行结果
环绕通知开始。。。。
RestController环绕通知开始。。。。
RestController环绕通知结束。。。。
环绕通知结束。。。。
暂时不确定一个配置类里面多个切入点执行顺序是如何设定的
多个配置类
package com.demo.springbootaop.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Aspect
@Order(2)
@Component
public class MyAspect {
/**
* 如何匹配切入点
* execution(返回值类型 包名.类名.方法名(参数))
* 更多匹配类型参考官方文档:<a href="https://docs.spring.io/spring-framework/reference/core/aop/ataspectj/pointcuts.html">...</a>
*/
@Pointcut("execution(* com.demo.springbootaop.controller.*.*(..))")
public void dsPointCut() {
}
/**
* 通知类型
* Around 环绕通知
* Before 前置通知
* AfterReturning 后置通知
* AfterThrowing 异常通知
* After 最终通知
*
*/
@Around("dsPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕通知开始。。。。 ");
Object proceed = point.proceed();
System.out.println("环绕通知结束。。。。 ");
return proceed;
}
}
package com.demo.springbootaop.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Aspect
@Order(1)
@Component
public class MyAspect1 {
//切入点
/**
* 根据注解切入
* "@Annotation(com.demo.springbootaop.annotation.MyAnnotation)"
*/
@Pointcut("(@within(org.springframework.web.bind.annotation.RestController))")
public void pcAnnotation() {
}
/**
* 如何匹配切入点
* execution(返回值类型 包名.类名.方法名(参数))
* 更多匹配类型参考官方文档:<a href="https://docs.spring.io/spring-framework/reference/core/aop/ataspectj/pointcuts.html">...</a>
*/
/**
* 通知类型
* Around 环绕通知
* Before 前置通知
* AfterReturning 后置通知
* AfterThrowing 异常通知
* After 最终通知
*
*/
@Around("pcAnnotation()")
public Object aroundRestController(ProceedingJoinPoint point) throws Throwable {
System.out.println("RestController环绕通知开始。。。。 ");
Object proceed = point.proceed();
System.out.println("RestController环绕通知结束。。。。 ");
return proceed;
}
}
执行结果
RestController环绕通知开始。。。。
环绕通知开始。。。。
环绕通知结束。。。。
RestController环绕通知结束。。。。
结论:
@Order(1)
值越小优先级越高
注意:环绕通知 先执行的后结束,后执行的先结束