對於 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方法開始記錄日誌了。。。最終");
}
}
}
測試異常通知: