spring aop 的五种通知类型
- 前置通知
Before advice
:在连接点前面执行,前置通知不会影响连接点的执行,除非此处抛出异常- 后置通知
After returning advice
:在连接点正常执行完成后执行,如果连接点抛出异常,则不会执行- 异常通知
After throwing advice
:在连接点抛出异常后执行- 最终通知
After (finally) advice
:在连接点执行完成后执行,不管是正常执行完成,还是抛出异常,都会执行返回通知中的内容- 环绕通知
Around advice
:环绕通知围绕在连接点前后,能在方法调用前后自定义一些操作,还需要负责决定是继续处理join point
(调用ProceedingJoinPoint
的proceed
方法)还是中断执行
五大通知类型中,环绕通知功能最为强大,因为环绕通知,可以控制目标方法是否执行。
如果需要记录异常信息,使用异常通知。
其他通知,只能做记录工作,不能做处理,所以执行顺序其实对整个程序影响不大,没有必要太深究。
spring aop 通知类型使用
添加 Aspect 切面类
package com.example.demo.module.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class AdviceTest {
// 配置织入点
@Pointcut("execution(public * com.example.demo.module.aspect.Test.*(..))")
public void test(){
}
@Before("test()")
public void doBefore(JoinPoint joinPoint){
System.out.println(joinPoint.getSignature().getName() + "执行前置通知---");
}
@AfterReturning("test()")
public void doAfterSuccess(JoinPoint joinPoint){
System.out.println(joinPoint.getSignature().getName() + "执行返回通知---");
}
@AfterThrowing("test()")
public void doAfterError(JoinPoint joinPoint){
System.out.println(joinPoint.getSignature().getName() + "执行异常通知---");
}
@Around(value = "test()", argNames = "pjp")
public Object doAround(ProceedingJoinPoint pjp) {
Object[] args = pjp.getArgs();
Object result;
try {
// Before
System.out.println(pjp.getSignature().getName() + "环绕前置通知---");
result = pjp.proceed(args);
// AfterReturning
System.out.println(pjp.getSignature().getName() + "环绕返回通知---");
}catch (Throwable e){
// AfterThrowing
System.out.println(pjp.getSignature().getName() + "环绕异常通知---");
throw new RuntimeException(e);
}finally {
// After
System.out.println(pjp.getSignature().getName() + "环绕最终通知---");
}
return result;
}
@After("test()")
public void doAfter(JoinPoint joinPoint){
System.out.println(joinPoint.getSignature().getName() + "执行最终通知---");
}
}
添加测试方法:
package com.example.demo.module.aspect;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("test")
@RestController
public class Test {
@GetMapping("testMethod")
public void testMethod(){
System.out.println("方法执行---");
}
}
运行结果:
测试异常通知,修改测试方法:
package com.example.demo.module.aspect;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("test")
@RestController
public class Test {
@GetMapping("testMethod")
public void testMethod(){
int i= 1/0;
System.out.println("方法执行---");
}
}
运行结果:
通知执行顺序
Spring 版本不一样,通知执行顺序可能也会存在差异
@Before、@After、@AfterReturning、@AfterThrowing执行顺序
- Spring 4.0
正常情况:@Before -> 目标方法 -> @After -> @AfterReturning
异常情况:@Before -> 目标方法 -> @After -> @AfterThrowing- Spring 5.28
正常情况:@Before -> 目标方法 -> @AfterReturning -> @After
异常情况:@Before -> 目标方法 -> @AfterThrowing -> @After
@Around的执行顺序
- Spring 4.0
正常情况:环绕前置 -> 目标方法执行 -> 环绕返回 -> 环绕最终
异常情况:环绕前置 -> 目标方法执行 -> 环绕异常 -> 环绕最终- Spring 5.28
正常情况:环绕前置 -> 目标方法执行 -> 环绕返回 -> 环绕最终
异常情况:环绕前置 -> 目标方法执行 -> 环绕异常 -> 环绕最终
五大通知执行顺序
- Spring 4.0
正常情况:环绕前置 -> @Before -> 目标方法执行 -> 环绕返回 -> 环绕最终 -> @After -> @AfterReturning
异常情况:环绕前置 -> @Before -> 目标方法执行 -> 环绕异常 -> 环绕最终 -> @After -> @AfterThrowing- Spring 5.28
正常情况:环绕前置 -> @Before -> 目标方法执行 -> @AfterReturning -> @After -> 环绕返回 -> 环绕最终
异常情况:环绕前置 -> @Before -> 目标方法执行 -> @AfterThrowing -> @After -> 环绕异常 -> 环绕最终