AOP 典型應用場景
- 1. 日志記錄(Logging)
- 代碼實現
- 2. 權限校驗(Authentication)
- 代碼實現
- 3. 性能監控(Performance Monitoring)
- 代碼實現
- 4. 緩存處理(Caching)
- 代碼實現
- 5. 重試機制(Retry)
- 代碼實現
- 6. 事務管理(Transaction Management)
- 代碼實現
- 7. 接口限流(Rate Limiting)
- 代碼實現
- 總結表格
1. 日志記錄(Logging)
場景:自動記錄方法的入參、返回值、執行時間和異常信息。
代碼實現
1. 自定義日志注解:
// annotation/Loggable.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {String tag() default "DEFAULT";
}
2. 切面邏輯:
// aop/LoggingAspect.java
@Aspect
@Component
public class LoggingAspect {private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);@Around("@annotation(loggable)")public Object logMethod(ProceedingJoinPoint pjp, Loggable loggable) throws Throwable {String methodName = pjp.getSignature().getName();String className = pjp.getTarget().getClass().getSimpleName();String tag = loggable.tag();// 記錄方法開始logger.info("[{}] {}.{}() 入參: {}", tag, className, methodName, Arrays.toString(pjp.getArgs()));long startTime = System.currentTimeMillis();try {Object result = pjp.proceed();long duration = System.currentTimeMillis() - startTime;// 記錄方法結束logger.info("[{}] {}.{}() 耗時: {}ms 返回: {}", tag, className, methodName, duration, result);return result;} catch (Exception e) {// 記錄異常logger.error("[{}] {}.{}() 異常: {}", tag, className, methodName, e.getMessage(), e);throw e;}}
}
3. 業務類使用:
// service/UserService.java
@Service
public class UserService {@Loggable(tag = "USER-SERVICE")public String getUserById(Long id) {return "User-" + id; // 模擬數據庫查詢}
}
4. 測試運行:
// MainApp.java
public class MainApp {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = context.getBean(UserService.class);userService.getUserById(123L);context.close();}
}
輸出結果:
[USER-SERVICE] UserService.getUserById() 入參: [123]
[USER-SERVICE] UserService.getUserById() 耗時: 2ms 返回: User-123
2. 權限校驗(Authentication)
場景:驗證用戶是否具有訪問特定方法的權限。
代碼實現
1. 自定義權限注解:
// annotation/RequireRole.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequireRole {String value() default "USER";
}
2. 切面邏輯:
// aop/SecurityAspect.java
@Aspect
@Component
public class SecurityAspect {// 模擬當前用戶角色private String currentUserRole = "ADMIN";@Before("@annotation(requireRole)")public void checkPermission(JoinPoint jp, RequireRole requireRole) {String requiredRole = requireRole.value();if (!requiredRole.equals(currentUserRole)) {throw new SecurityException("權限不足! 需要角色: " + requiredRole);}}
}
3. 業務類使用:
// service/AdminService.java
@Service
public class AdminService {@RequireRole("ADMIN")public void deleteDatabase() {System.out.println("數據庫已刪除!"); // 危險操作}
}
4. 測試運行:
public class MainApp {public static void main(String[] args) {try {AdminService adminService = context.getBean(AdminService.class);adminService.deleteDatabase();} catch (Exception e) {System.out.println("錯誤: " + e.getMessage());}}
}
輸出結果:
數據庫已刪除! // 如果currentUserRole="ADMIN"
錯誤: 權限不足! 需要角色: ADMIN // 如果currentUserRole="USER"
3. 性能監控(Performance Monitoring)
場景:統計方法執行耗時,用于性能分析。
代碼實現
1. 切面邏輯:
// aop/PerformanceAspect.java
@Aspect
@Component
public class PerformanceAspect {@Around("execution(* com.example.service.*.*(..))")public Object monitorPerformance(ProceedingJoinPoint pjp) throws Throwable {long start = System.currentTimeMillis();Object result = pjp.proceed();long duration = System.currentTimeMillis() - start;String methodName = pjp.getSignature().getName();System.out.println("方法 " + methodName + " 執行耗時: " + duration + "ms");return result;}
}
2. 業務類:
// service/DataProcessor.java
@Service
public class DataProcessor {public void process() throws InterruptedException {Thread.sleep(500); // 模擬耗時操作}
}
3. 測試輸出:
方法 process 執行耗時: 503ms
4. 緩存處理(Caching)
場景:緩存方法返回值,減少重復計算。
代碼實現
1. 自定義緩存注解:
// annotation/Cacheable.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cacheable {String keyPrefix() default "";int ttl() default 300; // 緩存時間(秒)
}
2. 切面邏輯:
// aop/CacheAspect.java
@Aspect
@Component
public class CacheAspect {private Map<String, Object> cache = new ConcurrentHashMap<>();@Around("@annotation(cacheable)")public Object handleCache(ProceedingJoinPoint pjp, Cacheable cacheable) throws Throwable {String key = cacheable.keyPrefix() + Arrays.toString(pjp.getArgs());if (cache.containsKey(key)) {System.out.println("從緩存獲取數據: " + key);return cache.get(key);}Object result = pjp.proceed();cache.put(key, result);System.out.println("將數據存入緩存: " + key);return result;}
}
3. 業務類使用:
// service/ProductService.java
@Service
public class ProductService {@Cacheable(keyPrefix = "product:")public String getProductInfo(String productId) {System.out.println("實際查詢數據庫...");return "Info-" + productId;}
}
4. 測試結果:
productService.getProductInfo("P100"); // 輸出: 實際查詢數據庫... 將數據存入緩存: product:[P100]
productService.getProductInfo("P100"); // 輸出: 從緩存獲取數據: product:[P100]
5. 重試機制(Retry)
場景:在方法執行失敗時自動重試。
代碼實現
1. 自定義重試注解:
// annotation/Retry.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Retry {int maxAttempts() default 3;
}
2. 切面邏輯:
// aop/RetryAspect.java
@Aspect
@Component
public class RetryAspect {@Around("@annotation(retry)")public Object retryOperation(ProceedingJoinPoint pjp, Retry retry) throws Throwable {int attempts = 0;Exception lastException;do {attempts++;try {return pjp.proceed();} catch (Exception e) {lastException = e;System.out.println("第 " + attempts + " 次嘗試失敗");}} while (attempts < retry.maxAttempts());throw lastException;}
}
3. 業務類使用:
// service/PaymentService.java
@Service
public class PaymentService {private int callCount = 0;@Retry(maxAttempts = 5)public void processPayment() {callCount++;if (callCount < 3) {throw new RuntimeException("支付網關超時");}System.out.println("支付成功!");}
}
4. 測試輸出:
第 1 次嘗試失敗
第 2 次嘗試失敗
支付成功!
6. 事務管理(Transaction Management)
場景:自動管理數據庫事務(簡化版示例)。
代碼實現
1. 事務管理器偽代碼:
// util/TransactionManager.java
@Component
public class TransactionManager {public void begin() {System.out.println("開啟事務");}public void commit() {System.out.println("提交事務");}public void rollback() {System.out.println("回滾事務");}
}
2. 切面邏輯:
// aop/TransactionAspect.java
@Aspect
@Component
public class TransactionAspect {@Autowiredprivate TransactionManager txManager;@Around("@annotation(com.example.annotation.Transactional)")public Object manageTransaction(ProceedingJoinPoint pjp) throws Throwable {txManager.begin();try {Object result = pjp.proceed();txManager.commit();return result;} catch (Exception e) {txManager.rollback();throw e;}}
}
3. 業務類使用:
// service/OrderService.java
@Service
public class OrderService {@Transactionalpublic void createOrder() {System.out.println("執行訂單創建邏輯...");// 模擬數據庫操作}
}
4. 測試輸出:
開啟事務
執行訂單創建邏輯...
提交事務
7. 接口限流(Rate Limiting)
場景:限制接口的調用頻率。
代碼實現
1. 限流注解:
// annotation/RateLimit.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {int value() default 5; // 每秒允許的最大請求數
}
2. 切面邏輯:
// aop/RateLimitAspect.java
@Aspect
@Component
public class RateLimitAspect {private Map<String, RateLimiter> limiters = new ConcurrentHashMap<>();@Around("@annotation(rateLimit)")public Object limit(ProceedingJoinPoint pjp, RateLimit rateLimit) throws Throwable {String methodName = pjp.getSignature().toShortString();RateLimiter limiter = limiters.computeIfAbsent(methodName, k -> RateLimiter.create(rateLimit.value()));if (limiter.tryAcquire()) {return pjp.proceed();} else {throw new RuntimeException("接口請求過于頻繁");}}
}
3. 業務類使用:
// service/ApiService.java
@Service
public class ApiService {@RateLimit(2) // 每秒最多2次調用public String getData() {return "敏感數據";}
}
總結表格
應用場景 | 核心注解 | 通知類型 | 關鍵實現技術 |
---|---|---|---|
日志記錄 | @Loggable | @Around | Slf4j + 方法元數據獲取 |
權限校驗 | @RequireRole | @Before | 權限上下文 + 條件判斷 |
性能監控 | 無(使用execution) | @Around | 時間計算 + 方法過濾 |
緩存處理 | @Cacheable | @Around | 本地緩存(ConcurrentHashMap) |
重試機制 | @Retry | @Around | 循環控制 + 異常捕獲 |
事務管理 | @Transactional | @Around | 事務管理器模擬 |
接口限流 | @RateLimit | @Around | RateLimiter + 方法標識管理 |
注意事項:
- 所有切面類必須被 Spring 掃描到(確保包路徑正確)
- 同類內部方法調用不會觸發 AOP(需通過代理對象調用)
- 性能敏感場景慎用 AOP(會增加方法調用棧深度)