对于 AOP 的知识在 Spring 学习章节已经进行过学习:一篇文章帮你搞定 Spring
本篇文章主要讲述如何在 SpringBoot 中使用 AOP
示例场景:比如项目已经上线,某个环节运行速度特别慢,需要对其单独打印日志测试一下,挨个去改很显然不靠谱,因此可以借助AOP,将该段代码嵌入到业务中,检测完成后,再移出掉即可。
一、前期配置
同时需要我们pom 中引入 aop 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
二、前置/后置/异常/最终通知的实现
这里的实现类似于:一篇文章帮你搞定 Spring 基于注解的AOP配置
目录结构:
UserService:
@Service
public class UserService {
public String getUsernameById(Integer id) {
System.out.println("UserService 执行 getUsernameById >>>> " + id);
return "Yolo";
}
public void getUsernameError(String name) {
System.out.println("UserService 执行 getUsernameByName >>>> " + name);
int i = 3/0;
}
}
UserController:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
UserService userService;
@GetMapping("/id")
public String getUserById(int id) {
return userService.getUsernameById(id);
}
@GetMapping("/error")
public void getError(){
System.out.println("进来了。。。。。。");
userService.getUsernameError("yolo");
}
}
LogComponent
@Component
@Aspect
public class LogComponent {
/**
* 对com.yolo.aop.service包下的所有方法进行增强
*/
@Pointcut("execution(* com.yolo.aop.service.*.*(..))")
public void pc1() {
}
//前置通知
@Before(value = "pc1()")
public void before(JoinPoint jp) {
String name = jp.getSignature().getName();
System.out.println("前置通知 >>> " + name);
}
//后置通知
@AfterReturning(value = "pc1()", returning = "result")
public void afterReturning(JoinPoint jp, Object result) {
String name = jp.getSignature().getName();
System.out.println("后置通知 >>> " + name + " >>> " + result);
}
//异常通知
@AfterThrowing(value = "pc1()", throwing = "e")
public void afterThrowing(JoinPoint jp, Exception e) {
String name = jp.getSignature().getName();
System.out.println("异常通知 >>> " + name + " >>> " + e.getMessage());
}
//最终通知
@After(value = "pc1()")
public void after(JoinPoint jp) {
String name = jp.getSignature().getName();
System.out.println("最终通知 >>> " + name);
}
}
测试异常通知:
三、环绕通知的实现
@Component
@Aspect
public class LogComponent {
/**
* 对com.yolo.aop.service包下的所有方法进行增强
*/
@Pointcut("execution(* com.yolo.aop.service.*.*(..))")
public void pc1() {
}
//环绕通知
@Around("pc1()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object rtValue = null;
try {
//得到方法执行所需的参数
Object[] args = pjp.getArgs();
System.out.println("args >>> " + args);
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。前置");
//明确调用业务层方法(切入点方法)
rtValue = pjp.proceed(args);
System.out.println("rtValue >>> " + rtValue);
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。后置");
return rtValue;
} catch (Throwable t) {
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常");
throw new RuntimeException(t);
} finally {
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终");
}
}
}
测试异常通知: