在業務方法上打注解
package com.lib.service;@Service
public class BookService {@LogExecution(description = "查詢圖書")public Book query(int id) {return repo.findById(id);}@LogExecution(description = "借閱圖書")public void borrow(int id) {// 模擬異常 50%if (Math.random() < 0.5) throw new RuntimeException("庫存不足");}
}
5. 測試 & 觀察
啟動 Tomcat
瀏覽器訪問
http://localhost:8080/library/book/1
多刷幾次,控制臺出現:
[AOP-LOG] BookService.query | desc=查詢圖書 | cost=3 ms | status=SUCCESS
[AOP-LOG] BookService.borrow | desc=借閱圖書 | cost=1 ms | status=ERROR | msg=庫存不足
6. 多切面執行順序
再寫一個 安全切面:
@Aspect
@Component
@Order(1) // 值越小越先執行
public class SecurityAspect {@Before("@annotation(LogExecution)")public void check() {System.out.println("[SECURITY] 權限校驗通過");}
}
重啟后觀察日志順序:
[SECURITY] 權限校驗通過
[AOP-LOG] BookService.query ...
7. 底層實現速看
打開 IDEA → 雙擊 Shift → 輸入
AnnotationAwareAspectJAutoProxyCreator
該類負責 后置處理器 生成代理。在
LoggingAspect.logAround()
第一行打斷點,以 Debug 模式啟動:
調用棧能看到CglibAopProxy
→DynamicAdvisedInterceptor
→MethodInterceptor
。結論:Spring 默認使用 CGLIB 代理類(無接口也能代理),若類實現接口也可強制用 JDK 動態代理(
@EnableAspectJAutoProxy(proxyTargetClass=false)
)。
8. 單元測試
@SpringJUnitConfig(AppConfig.class)
@EnableAspectJAutoProxy
class AopTests {@AutowiredBookService bookService;@Testvoid queryShouldPrintLog() {bookService.query(1); // 控制臺應出現 AOP-LOG}
}