在通知(Advice)中获取目标方法的参数和返回值是 AOP 中非常常见的操作,这使得我们的切面逻辑可以根据输入和输出来做出不同的响应。
1. 获取目标方法的参数
几乎所有的通知类型(@Before, @After, @Around 等)都可以通过注入 JoinPoint 对象来轻松获取方法的参数。
方法:使用 JoinPoint.getArgs()
JoinPoint 接口提供了一个 getArgs() 方法,它会返回一个 Object[] 数组,其中包含了调用目标方法时传入的所有参数,顺序与方法签名中的参数顺序一致。
示例:
假设我们有这样一个服务方法:
@Service
public class UserService {
public User findUser(Long id, String name) {
// ... 业务逻辑
return new User(id, name);
}
}
我们可以这样在 @Before 通知中获取并打印它的参数:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Aspect
@Component
public class ParameterLoggingAspect {
@Before("execution(* com.example.service.UserService.findUser(..))")
public void logMethodParameters(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
// 使用 getArgs() 获取参数数组
Object[] args = joinPoint.getArgs();
System.out.printf("方法 [%s] 即将执行,参数为: %s%n", methodName, Arrays.toString(args));
// 你也可以单独访问每个参数
if (args.length > 0 && args[0] instanceof Long) {
Long userId = (Long) args[0];
System.out.println("用户 ID 是: " + userId);
}
}
}
当你调用 userService.findUser(101L, "Alice") 时,控制台会输出:
方法 [findUser] 即将执行,参数为: [101, Alice]
用户 ID 是: 101
2. 获取目标方法的返回值
获取返回值稍微特殊一些,因为它只在方法成功执行并返回后才有意义。因此,只有 @AfterReturning 和 @Around 这两种通知可以获取到返回值。
方法一:使用 @AfterReturning 的 returning 属性 (推荐)
这是专门用于处理返回值的通知,也是最直接、最清晰的方式。
- 你需要在
@AfterReturning注解中指定returning属性,它的值是一个字符串,这个字符串必须与通知方法中的一个参数名完全匹配。 - Spring AOP 会自动将目标方法的返回值赋给这个参数。
示例:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class ReturnValueLoggingAspect {
/**
* @param joinPoint 用于获取方法信息
* @param returnValue 用于接收返回值,参数名必须与 "returning" 属性的值匹配
*/
@AfterReturning(
pointcut = "execution(* com.example.service.UserService.findUser(..))",
returning = "returnValue" // 关键:指定接收返回值的参数名
)
public void logMethodReturnValue(JoinPoint joinPoint, Object returnValue) {
String methodName = joinPoint.getSignature().getName();
System.out.printf("方法 [%s] 成功执行,返回值为: %s%n", methodName, returnValue);
// 你可以对返回值做进一步处理,比如检查它是否为 null,或者是什么类型
if (returnValue instanceof User) {
User user = (User) returnValue;
System.out.println("返回的用户对象的名字是: " + user.getName());
}
}
}
当你调用 userService.findUser(101L, "Alice") 时,控制台会输出:
方法 [findUser] 成功执行,返回值为: User{id=101, name='Alice'}
返回的用户对象的名字是: Alice
重要提示:
- 如果目标方法是
void类型,@AfterReturning通知依然会执行,但接收到的returnValue将会是null。 - 如果目标方法抛出异常,
@AfterReturning通知不会执行。
方法二:使用 @Around (功能更强大,也更复杂)
环绕通知通过调用 ProceedingJoinPoint.proceed() 来执行目标方法,这个方法的返回值就是目标方法的返回值。
示例:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class AroundAspect {
@Around("execution(* com.example.service.UserService.findUser(..))")
public Object logAndModifyReturnValue(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("[环绕通知] 方法执行前...");
// 执行目标方法,并捕获返回值
Object result = pjp.proceed();
System.out.println("[环绕通知] 方法执行后,原始返回值为: " + result);
// 在这里,你甚至可以修改返回值!
if (result instanceof User) {
User user = (User) result;
user.setName(user.getName() + " [Processed by AOP]");
return user; // 返回修改后的对象
}
return result; // 返回原始值
}
}
在这种情况下,调用方最终收到的 User 对象的 name 属性会被附加 [Processed by AOP] 的后缀。
总结
| 需求 | 使用哪种通知 | 如何实现 | 备注 |
|---|---|---|---|
| 获取参数 | @Before, @After, @AfterReturning, @AfterThrowing, @Around | 注入 JoinPoint,调用 getArgs() 方法。 | 通用且简单。 |
| 获取返回值 | @AfterReturning | 使用 returning 属性将返回值绑定到通知方法的参数上。 | 推荐,意图清晰,专门用于处理返回结果。 |
| 获取并修改返回值 | @Around | 调用 pjp.proceed() 捕获返回值,然后处理或返回一个新的值。 | 功能最强大,但需要手动管理方法执行流程。 |
257

被折叠的 条评论
为什么被折叠?



