日志、事務、安全、緩存等功能分散在各業務模塊中,導致代碼耦合、重複、難維護。AOP 將這些橫切關注點 模塊化為切面,通過聲明式方式織入業務邏輯,實現關注點分離。
| 術語 | 英文 | 核心含義 |
|---|---|---|
| 通知 | Advice | 切面具體執行的邏輯(做什麼、何時做) |
| 連接點 | Join Point | 程序執行中可插入切面的點(方法調用、異常拋出、字段訪問) |
| 切點 | Pointcut | 匹配連接點的條件表達式,定義「在何處」織入 |
| 切面 | Aspect | 通知 + 切點 = 完整切面定義 |
| 引入 | Introduction | 為現有類動態添加方法/字段/接口實現 |
| 織入 | Weaving | 將切面應用到目標對象創建代理的過程 |
@Aspect
public class LoggingAspect {
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}
// 1. 前置通知:方法執行前
@Before("serviceLayer()")
public void before(JoinPoint jp) {
log.info("Enter: {}", jp.getSignature());
}
// 2. 後置通知:方法正常返回後
@AfterReturning(pointcut = "serviceLayer()", returning = "result")
public void afterReturn(JoinPoint jp, Object result) {
log.info("Exit: {} -> {}", jp.getSignature(), result);
}
// 3. 異常通知:方法拋出異常後
@AfterThrowing(pointcut = "serviceLayer()", throwing = "ex")
public void afterThrow(JoinPoint jp, Exception ex) {
log.error("Exception: {}", ex.getMessage());
}
// 4. 最终通知:無論正常/異常都執行 (finally)
@After("serviceLayer()")
public void afterFinally(JoinPoint jp) {
// 清理資源、釋放鎖等
}
// 5. 環繞通知:完全控制方法執行 (最強大、最複雜)
@Around("serviceLayer()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
try {
Object result = pjp.proceed(); // 繼續執行目標方法
return result;
} finally {
log.info("Duration: {}ms", System.currentTimeMillis() - start);
}
}
}

<aop:config>、<aop:aspect> 純 XML 聲明ProxyFactoryBean 程序化配置,歷史遺留execution(public * com.example..*.*(..)) // 包及子包所有公共方法 execution(* *..service.*.*(..)) // service 包下所有方法 @annotation(com.example.Loggable) // 帶特定註解的方法 this(com.example.ServiceInterface) // 代理實現指定接口 target(com.example.ServiceImpl) // 目標對象類型 args(java.io.Serializable) // 參數類型匹配 @within(org.springframework.transaction.annotation.Transactional) // 類級註解 bean(*Service) // Bean 名稱模式 (Spring 專有)