以下是Spring AOP中為所有類型通知傳遞參數的完整示例,包含詳細注釋和參數傳遞方式:
// 1. 目標類(被增強的類)
package com.example;public class TargetService {public void doTask(String param) {System.out.println("執行業務邏輯,參數:" + param);}public void doTaskWithoutParam() {System.out.println("執行無參業務邏輯");}public void doTaskWithError() throws Exception {System.out.println("執行會拋異常的邏輯");throw new RuntimeException("模擬異常");}
}
// 2. 切面類(包含所有通知類型)
package com.example;import org.aspectj.lang.*;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Aspect
@Component
public class ParameterAspect {// 前置通知:通過JoinPoint獲取參數@Before("execution(* com.example.TargetService.*(..))")public void beforeAdvice(JoinPoint joinPoint) {System.out.println("前置通知:方法開始");Object[] args = joinPoint.getArgs();for (Object arg : args) {System.out.println("參數值:" + arg);}}// 后置通知:返回值和參數@AfterReturning(pointcut = "execution(* com.example.TargetService.*(..))",returning = "result")public void afterReturningAdvice(JoinPoint joinPoint, Object result) {System.out.println("后置通知:方法正常返回");System.out.println("返回值:" + result);System.out.println("參數列表:" + joinPoint.getArgs());}// 異常通知:捕獲異常和參數@AfterThrowing(pointcut = "execution(* com.example.TargetService.*(..))",throwing = "ex")public void afterThrowingAdvice(JoinPoint joinPoint, Throwable ex) {System.out.println("異常通知:方法拋出異常");System.out.println("異常信息:" + ex.getMessage());System.out.println("異常發生時的參數:" + joinPoint.getArgs());}// 環繞通知:直接操作ProceedingJoinPoint@Around("execution(* com.example.TargetService.*(..))")public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {System.out.println("環繞通知:方法執行前");System.out.println("方法參數:" + pjp.getArgs());try {Object result = pjp.proceed();System.out.println("環繞通知:方法執行后");return result;} catch (Throwable ex) {System.out.println("環繞通知:捕獲異常");throw ex;}}// 引介通知:不直接傳遞參數(示例展示引入接口)@DeclareParents(value = "com.example.TargetService+",defaultImpl = AuditLogImpl.class)private AuditLog auditLog;private static class AuditLogImpl implements AuditLog {@Overridepublic void log() {System.out.println("引介通知:記錄審計日志");}}
}
// 3. Spring配置類
package com.example;import org.springframework.context.annotation.*;@Configuration
@ComponentScan("com.example")
@EnableAspectJAutoProxy
public class AppConfig {@Beanpublic TargetService targetService() {return new TargetService();}
}
// 4. 測試類
public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);TargetService service = context.getBean(TargetService.class);// 測試正常流程service.doTask("參數1");// 測試無參方法service.doTaskWithoutParam();// 測試異常流程try {service.doTaskWithError();} catch (Exception e) {System.out.println("捕獲到異常:" + e.getMessage());}// 測試引介接口AuditLog audit = (AuditLog) service;audit.log();}
}
關鍵點總結表格:
通知類型 | 參數傳遞方式 | 示例代碼片段 | 參數來源說明 |
---|---|---|---|
前置通知 | JoinPoint.getArgs() | Object[] args = joinPoint.getArgs(); | 直接獲取方法參數數組 |
后置通知 | JoinPoint + 返回值參數 | public void afterReturningAdvice(JoinPoint joinPoint, Object result) | 返回值通過returning 參數獲取 |
異常通知 | JoinPoint + 異常參數 | public void afterThrowingAdvice(JoinPoint joinPoint, Throwable ex) | 異常對象通過throwing 參數獲取 |
環繞通知 | ProceedingJoinPoint | pjp.proceed() | 包含完整方法控制權 |
引介通知 | 不直接傳遞參數(接口綁定) | @DeclareParents | 通過接口實現間接關聯 |
執行結果:
前置通知:方法開始
參數值:參數1
環繞通知:方法執行前
方法參數:[參數1]
執行業務邏輯,參數:參數1
環繞通知:方法執行后
后置通知:方法正常返回
返回值:null
參數列表:[參數1]前置通知:方法開始
環繞通知:方法執行前
方法參數:[]
執行無參業務邏輯
環繞通知:方法執行后
后置通知:方法正常返回
返回值:null
參數列表:[]前置通知:方法開始
環繞通知:方法執行前
方法參數:[]
執行會拋異常的邏輯
異常通知:方法拋出異常
異常信息:模擬異常
異常發生時的參數:[]
環繞通知:捕獲異常
捕獲到異常:模擬異常引介通知:記錄審計日志
核心要點:
- JoinPoint:所有通知(除環繞)都通過
JoinPoint
對象獲取參數 - ProceedingJoinPoint:環繞通知特有的接口,支持手動執行目標方法
- 參數綁定:通過注解屬性(如
returning
/throwing
)聲明額外參數 - 參數類型:參數類型需與目標方法參數匹配,可通過
joinPoint.getSignature()
獲取方法元數據 - 引介通知:主要用于類型增強,不直接參與參數傳遞