| 註解 | 類型 | 執行時機 | 典型用途 |
|---|---|---|---|
@Before | 前置通知 | 方法執行之前 | 權限檢查、事務開啟、日誌記錄 |
@After | 後置通知 | 方法執行之後(無論正常/異常) | 資源清理、事務提交/回滾 |
@AfterReturning | 返回通知 | 方法正常返回後 | 返回值處理、緩存更新、審計日誌 |
@AfterThrowing | 異常通知 | 方法拋出異常後 | 異常轉換、錯誤通知、補償操作 |
@Around | 環繞通知 | 完全控制方法執行流程 | 性能監控、重試機制、事務邊界控制 |
aspectjrt.jar、aspectjweaver.jaraop namespace:xmlns:aop="https://www.springframework.org/schema/aop"<aop:aspectj-autoproxy/>package www.csdn.spring.advice.aspetjs;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
@Aspect
public class AdviceImpl {
// 前置通知:匹配 UserDaoImpl 所有方法
@Before("execution(* UserDaoImpl.*(..))")
public void doTransAction() {
System.out.println("----開啟事務-----");
}
// 後置通知:匹配 www.csdn 包下 UserDaoImpl 所有方法
@After("execution(* www.csdn..UserDaoImpl.*(..))")
public void doAfterTransAction() {
System.out.println("-------提交事務-------");
}
// 環繞通知:僅匹配 save 方法,演示 ProceedingJoinPoint 用法
@Around("execution(* www.csdn..UserDaoImpl.save(..))")
public void doSec(ProceedingJoinPoint jp) {
System.out.println("----------安全處理之前-------------");
try {
Object obj = jp.proceed(); // 執行目標方法
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("----------安全處理之後-------------");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:aop="https://www.springframework.org/schema/aop"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 切面 Bean -->
<bean id="adviceImpl" class="www.csdn.spring.advice.aspetjs.AdviceImpl"/>
<!-- 目標 Bean -->
<bean id="userDaoImpl" class="www.csdn.spring.advice.aspetjs.UserDaoImpl"/>
<!-- 啟用 @AspectJ 自動代理 -->
<aop:aspectj-autoproxy/>
</beans>
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-asp*.xml");
UserDao uDao = (UserDao) context.getBean("userDaoImpl");
uDao.save(null);
// uDao.delete(null);
// uDao.update(null);
// uDao.getObjects();
}
@Before("execution(* com.service..*.*(..))")
public void logBefore(JoinPoint jp) {
Signature sig = jp.getSignature(); // 方法簽名
String methodName = sig.getName();
Object[] args = jp.getArgs(); // 參數數組
System.out.println("調用: " + methodName + ", 參數: " + Arrays.toString(args));
}
@AfterReturning(pointcut = "execution(* com.service..*.*(..))", returning = "result")
public void logAfterReturn(JoinPoint jp, Object result) {
System.out.println("返回值: " + result);
}
@AfterThrowing(pointcut = "execution(* com.service..*.*(..))", throwing = "ex")
public void logException(JoinPoint jp, Exception ex) {
System.err.println("異常: " + ex.getMessage());
}
@Around("execution(* com.service..*.*(..))")
public Object around(ProceedingJoinPoint jp) throws Throwable {
long start = System.currentTimeMillis();
Object result = jp.proceed(); // 繼續執行目標方法
long elapsed = System.currentTimeMillis() - start;
System.out.println("耗時: " + elapsed + "ms");
return result; // 必須返回結果
}
警示:環繞通知必須調用 jp.proceed() 且返回其結果,否則目標方法不執行或調用方拿不到返回值。
@Aspect
@Order(0) // 值越小,優先級越高(最先執行)
public class SecurityAspect { ... }
@Aspect
@Order(1)
public class TransactionAspect { ... }
@Aspect
public class CommonPointcuts {
@Pointcut("execution(* com.example.service..*.*(..))")
public void serviceLayer() {}
@Pointcut("execution(* com.example.dao..*.*(..))")
public void dataAccessLayer() {}
@Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
public void transactionalMethods() {}
}
// 其他切面引用
@Before("CommonPointcuts.serviceLayer()")
public void doSomething() { ... }
<aop:aspectj-autoproxy/> 已配置、切面 Bean 被容器掃描(@Component 或 XML 定義)returning/throwing 參數名必須與方法參數名一致