SpringAop使用
此文章直接进入aop的使用,aop的相关概念请自行补:
推荐链接: https://blog.csdn.net/q982151756/article/details/80513340
进入正题。
Advice 的5种类型:
- before advice, 在 join point 前被执行的 advice. 虽然 before advice 是在 join point 前被执行, 但是它并不能够阻止 join point 的执行, 除非发生了异常(即我们在 before advice 代码中, 不能人为地决定是否继续执行 join point 中的代码)。
- after return advice, 在一个 join point 正常返回后执行的 advice。
- after throwing advice, 当一个 join point 抛出异常后执行的 advice。
- after(final) advice, 无论一个 join point 是正常退出还是发生了异常, 都会被执行的 advice.。
- around advice, 在 join point 前和 joint point 退出后都执行的 advice. 这个是最常用的 advice.
实例代码:
一:前置通知: @Before
1、先建一个切面类,声明切入点,写前置通知逻辑。
@Aspect @Component public class AspectTest { //切入点 @Pointcut("execution(* com.tan.controller..*(..))") public void testAspect() { } @Before(value = "testAspect()") public void before() { System.out.println("前置通知"); } }
测试代码,后续都是调这个接口测试:
@GetMapping("/aop") public String aopTest(String id,String name) { //System.out.println("请求参数:"+id+",name:"+name); System.out.println("this is method"); //int a = 10 / 0; return "这是方法执行的返回结果"; }
运行结果:
二:后置通知:@AfterReturning
@AfterReturning(value = "testAspect()") public void afterReturning() { System.out.println("方法执行后而且没有异常后的通知"); }
三:异常通知 : @AfterThrowing
@AfterThrowing(value = "testAspect()") public void afterThrowing() { System.out.println("异常后通知"); }
@GetMapping("/aop")
public String aopTest(String id,String name) {
//System.out.println("请求参数:"+id+",name:"+name);
System.out.println("this is method");
int a = 10 / 0;
return "aop";
}
四:最终通知 :@After
@After(value = "testAspect()")
public void after(JoinPoint joinPoint) {
System.out.println("后置通知");
}
五:环绕通知:@Around
@Around(value = "testAspect()") public Object test(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕通知: 方法前,test先执行了"); //环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的. //确实是order越小越是最先执行,但更重要的是最先执行的最后结束 //Thread.sleep(5000); Object s = proceedingJoinPoint.proceed(); // System.out.println("方法名:" + proceedingJoinPoint.getSignature()); // System.out.println("方法参数+"+ Arrays.toString(proceedingJoinPoint.getArgs())); //System.out.println("s是: " + s); System.out.println("环绕通知: 方法后"); return ""; }
ProceedingJoinPoint 类的一些常用方法:
//启动目标方法执行 :proceedingJoinPoint.proceed() Object s = proceedingJoinPoint.proceed(); //获取方法名:proceedingJoinPoint.getSignature() System.out.println("方法名:" + proceedingJoinPoint.getSignature()); //获取方法参数:proceedingJoinPoint.getArgs() System.out.println("方法参数:" + Arrays.toString(proceedingJoinPoint.getArgs()));
spring 多个切面的执行顺序及原理:
https://blog.csdn.net/qq_32317661/article/details/112310508
直接总结:
这里用注解的方式:在类上加上 @Order(1)
order越小越是最先执行,但更重要的是最先执行的最后结束。
这个不难理解,Spring AOP就是面向切面编程,什么是切面,画一个图来理解下:
由此得出:spring aop就是一个同心圆,要执行的方法为圆心,最外层的order最小。从最外层按照AOP1、AOP2的顺序依次执行doAround方法,doBefore方法。然后执行method方法,最后按照AOP2、AOP1的顺序依次执行doAfter、doAfterReturn方法。也就是说对多个AOP来说,先before的,一定后after。
如果我们要在同一个方法事务提交后执行自己的AOP,那么把事务的AOP order设置为2,自己的AOP order设置为1,然后在doAfterReturn里边处理自己的业务逻辑。
总结:
如果两个切面中覆写的getOrder方法中返回的是0,就是还没有显式的指定不同的顺序,所以,根据跟踪源码,可以发现在order相同的情况下, 是根据切面类的名称字母序进行优先级控制的,字母序越靠前,优先级越高。字母序的比较,首先将类名转换为字符串,然后调用String的compareTo()方法,对两个类名进行比对,决定切面的排序的。如果切面类使用了@Order注解或者是实现了Ordered接口,那么可以在比对的时候自动调用getOrder()的方法,然后比较返回的值大小,值越小,优先级越高。
同一个切面类中的方法,如果有多个不同的切入方式,例如@Around,@Before,@After,@AfterReturning,@AfterThrowing,那么会先扫描出各个方法上的注解,对不同的方法按照上边注解的顺序进行排序,然后按照字母序进行排序,所以最终呈现出来的,同一个切面类中的不同切面方法的执行顺序,就会呈现如上所示的状态。