当然可以!下面我为您详细展示 Spring AOP 中各种 Advice 的实现示例,包括 @Before、@AfterReturning、@AfterThrowing、@After 和 @Around。
1. @Before - 前置通知
在目标方法执行之前执行,适用于参数校验、权限检查、日志记录等场景。
基础实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| @Aspect @Component public class BeforeAdviceExample {
@Before("execution(* com.example.service.UserService.*(..))") public void logBeforeMethod() { System.out.println("【Before】准备执行方法..."); }
@Before("execution(* com.example.service.*.*(..))") public void logBeforeWithJoinPoint(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); String className = joinPoint.getTarget().getClass().getSimpleName(); Object[] args = joinPoint.getArgs(); System.out.println("【Before】执行 " + className + "." + methodName); System.out.println("【Before】参数: " + Arrays.toString(args)); }
@Before("execution(* com.example.service.UserService.createUser(..)) && args(user,..)") public void validateUser(JoinPoint joinPoint, User user) { if (user.getName() == null || user.getName().trim().isEmpty()) { throw new IllegalArgumentException("用户名不能为空"); } if (user.getAge() < 0 || user.getAge() > 150) { throw new IllegalArgumentException("年龄不合法"); } System.out.println("【Before】用户参数校验通过"); }
@Before("execution(* com.example.service.AdminService.*(..))") public void checkPermission(JoinPoint joinPoint) { SecurityContext context = SecurityUtils.getContext(); if (!context.hasRole("ADMIN")) { throw new SecurityException("无权限执行该操作"); } System.out.println("【Before】权限检查通过"); } }
|
2. @AfterReturning - 返回后通知
在目标方法成功执行并返回结果后执行,适用于处理返回结果、记录成功日志等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| @Aspect @Component public class AfterReturningAdviceExample {
@AfterReturning("execution(* com.example.service.UserService.findUser(..))") public void logAfterReturning() { System.out.println("【AfterReturning】方法执行成功"); }
@AfterReturning( pointcut = "execution(* com.example.service.UserService.findUser(..))", returning = "result" ) public void logReturnValue(JoinPoint joinPoint, Object result) { String methodName = joinPoint.getSignature().getName(); if (result != null) { System.out.println("【AfterReturning】方法 " + methodName + " 返回: " + result); } else { System.out.println("【AfterReturning】方法 " + methodName + " 返回 null"); } }
@AfterReturning( pointcut = "execution(* com.example.service.UserService.getUserStats(..))", returning = "stats" ) public void processStats(UserStats stats) { if (stats != null) { System.out.println("【AfterReturning】处理用户统计: " + stats.getTotalUsers()); stats.setProcessedTime(new Date()); } }
@AfterReturning("execution(* com.example.service.FileService.uploadFile(..))") public void cleanupTempFiles(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); if (args.length > 0 && args[0] instanceof String fileName) { System.out.println("【AfterReturning】清理临时文件: " + fileName); } } }
|
3. @AfterThrowing - 异常通知
在目标方法抛出异常后执行,适用于异常处理、错误日志记录、事务回滚等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| @Aspect @Component public class AfterThrowingAdviceExample {
@AfterThrowing("execution(* com.example.service.*.*(..))") public void logAfterThrowing() { System.out.println("【AfterThrowing】方法执行出现异常"); }
@AfterThrowing( pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex" ) public void logExceptionDetails(JoinPoint joinPoint, Exception ex) { String methodName = joinPoint.getSignature().getName(); String className = joinPoint.getTarget().getClass().getSimpleName(); System.err.println("【AfterThrowing】" + className + "." + methodName + " 发生异常: " + ex.getMessage()); System.err.println("【AfterThrowing】异常类型: " + ex.getClass().getSimpleName()); }
@AfterThrowing( pointcut = "execution(* com.example.service.UserService.*(..))", throwing = "ex" ) public void handleUserServiceException(JoinPoint joinPoint, UserNotFoundException ex) { System.err.println("【AfterThrowing】用户未找到异常: " + ex.getUserId()); }
@AfterThrowing( pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex" ) public void handleDataAccessException(JoinPoint joinPoint, DataAccessException ex) { String methodName = joinPoint.getSignature().getName(); System.err.println("【AfterThrowing】数据库访问异常 in " + methodName + ": " + ex.getMessage()); } }
|
4. @After - 后置通知(Finally通知)
在目标方法执行之后执行,无论成功还是异常都会执行,适用于资源清理、释放连接等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| @Aspect @Component public class AfterAdviceExample {
@After("execution(* com.example.service.FileService.*(..))") public void cleanupResources() { System.out.println("【After】执行资源清理"); }
@After("execution(* com.example.service.*.*(..))") public void logMethodCompletion(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("【After】方法 " + methodName + " 执行完成(无论成功或失败)"); }
@After("execution(* com.example.service.DatabaseService.executeQuery(..))") public void releaseDatabaseResources(JoinPoint joinPoint) { try { System.out.println("【After】释放数据库资源"); } catch (Exception e) { System.err.println("【After】资源释放失败: " + e.getMessage()); } }
@After("execution(* com.example.service.FileService.*(..))") public void cleanupFileHandles(JoinPoint joinPoint) { System.out.println("【After】清理文件句柄和流资源"); } }
|
5. @Around - 环绕通知(功能最强大)
包围着目标方法的执行,可以控制是否执行目标方法、修改参数、处理返回值等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
| @Aspect @Component public class AroundAdviceExample {
@Around("execution(* com.example.service.*.*(..))") public Object measureExecutionTime(ProceedingJoinPoint pjp) throws Throwable { long startTime = System.currentTimeMillis(); try { Object result = pjp.proceed(); return result; } finally { long endTime = System.currentTimeMillis(); long duration = endTime - startTime; String methodName = pjp.getSignature().getName(); System.out.println("【Around】方法 " + methodName + " 执行耗时: " + duration + "ms"); if (duration > 1000) { System.out.println("【Around】警告: " + methodName + " 执行时间过长!"); } } }
@Around("execution(* com.example.service.UserService.findUserById(Long)) && args(userId)") public Object cacheUser(ProceedingJoinPoint pjp, Long userId) throws Throwable { String cacheKey = "user:" + userId; Object cachedValue = CacheManager.get(cacheKey); if (cachedValue != null) { System.out.println("【Around】从缓存获取用户: " + userId); return cachedValue; } System.out.println("【Around】缓存未命中,查询数据库: " + userId); Object result = pjp.proceed(); if (result != null) { CacheManager.put(cacheKey, result, 300); System.out.println("【Around】用户数据已缓存: " + userId); } return result; }
@Around("execution(* com.example.service.ExternalService.callApi(..))") public Object retryOnFailure(ProceedingJoinPoint pjp) throws Throwable { int maxRetries = 3; int retryCount = 0; Exception lastException = null; while (retryCount < maxRetries) { try { System.out.println("【Around】第 " + (retryCount + 1) + " 次尝试"); return pjp.proceed(); } catch (Exception e) { lastException = e; retryCount++; System.out.println("【Around】调用失败,准备重试: " + e.getMessage()); if (retryCount < maxRetries) { Thread.sleep(1000 * retryCount); } } } throw new RuntimeException("方法执行失败,重试 " + maxRetries + " 次后仍失败", lastException); }
@Around("execution(* com.example.service.UserService.updateUser(..)) && args(user)") public Object validateAndProcessUser(ProceedingJoinPoint pjp, User user) throws Throwable { if (user.getId() == null) { throw new IllegalArgumentException("用户ID不能为空"); } user.setUpdatedAt(new Date()); user.setUpdatedBy(getCurrentUserId()); System.out.println("【Around】参数校验和处理完成,准备执行方法"); Object[] args = pjp.getArgs(); Object result = pjp.proceed(args); if (result instanceof Boolean && (Boolean) result) { System.out.println("【Around】用户更新成功"); return new OperationResult(true, "更新成功"); } return result; }
@Around("execution(* com.example.service.AdminService.manageSystem(..))") public Object checkPermissionAndWrapResult(ProceedingJoinPoint pjp) throws Throwable { if (!hasAdminPermission()) { return new OperationResult(false, "权限不足"); } try { Object result = pjp.proceed(); return new OperationResult(true, "操作成功", result); } catch (BusinessException e) { return new OperationResult(false, e.getMessage()); } } private boolean hasAdminPermission() { return SecurityUtils.getCurrentUser().hasRole("ADMIN"); } private String getCurrentUserId() { return "user123"; } }
|
辅助类定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| @Data class User { private Long id; private String name; private Integer age; private Date updatedAt; private String updatedBy; }
class UserStats { private int totalUsers; private Date processedTime; }
class OperationResult { private boolean success; private String message; private Object data; public OperationResult(boolean success, String message) { this.success = success; this.message = message; } public OperationResult(boolean success, String message, Object data) { this.success = success; this.message = message; this.data = data; } }
class UserNotFoundException extends RuntimeException { private Long userId; public UserNotFoundException(Long userId) { super("用户未找到: " + userId); this.userId = userId; } public Long getUserId() { return userId; } }
class SecurityUtils { public static SecurityContext getContext() { return new SecurityContext(); } public static User getCurrentUser() { return new User(); } }
class CacheManager { public static Object get(String key) { return null; } public static void put(String key, Object value, int seconds) {} }
class SecurityContext { public boolean hasRole(String role) { return true; } }
|
这些示例涵盖了 Spring AOP 中各种 Advice 的常见使用场景,您可以根据实际需求进行修改和扩展。