AspectJ/Spring AOP拦截方法时如何获取调用方方法的入参
问题前提说明
你当前的用法存在两个核心限制:
- 默认Spring AOP是基于动态代理实现,仅能拦截Spring容器托管的Bean的方法执行,你代码中的Ent是自行new出来的实例,execution切入点根本无法拦截到getSth方法的执行。
- Spring AOP仅支持execution类型切入点,不支持call切入点,也无法直接获取调用方方法的上下文参数。
所以最优解是切换到AspectJ实现,无需修改业务代码即可实现需求。
方案一:使用AspectJ(推荐,无侵入,性能稳定)
首先需要为项目开启AspectJ的编译时织入(CTW)或者加载时织入(LTW),即可支持call切入点和调用方上下文获取。
切面代码实现
如果调用getSth的上层方法签名统一(都是入参为Integer的shouldDoSthAndCallMethodGetSth),可以直接绑定参数:
@Aspect public class GettingSthAdvisor { @Before("call(* com.example.demo.aspects.Ent.getSth()) && withincode(* com.example.demo..*.shouldDoSthAndCallMethodGetSth(Integer)) && args(callerParam)") public void beforeGetSthCall(Integer callerParam) { // callerParam就是你要的666、999这类上层入参 // 你的参数处理逻辑 } }
如果上层调用方方法名不统一,可通过封闭连接点直接获取所有上层方法入参:
@Aspect public class GettingSthAdvisor { @Around("call(* com.example.demo.aspects.Ent.getSth())") public Object aroundGetSthCall(ProceedingJoinPoint pjp) throws Throwable { // 获取上层调用方法的所有入参数组 Object[] callerArgs = pjp.getEnclosingJoinPoint().getArgs(); // 按业务逻辑提取需要的参数即可,比如提取第一个Integer类型参数 for (Object arg : callerArgs) { if (arg instanceof Integer) { Integer callerParam = (Integer) arg; // 你的参数处理逻辑 break; } } return pjp.proceed(); } }
方案二:基于Spring AOP实现(侵入性高,仅适合不愿意引入AspectJ织入的场景)
需要修改两处核心逻辑:
- 把Ent类交给Spring容器托管,禁止自行new实例,否则无法被Spring AOP拦截
- 通过ThreadLocal透传参数,需要修改所有调用方的业务代码:
1. 定义参数传递的ThreadLocal工具类
public class CallerParamHolder { private static final ThreadLocal<Integer> PARAM_HOLDER = new ThreadLocal<>(); public static void set(Integer param) { PARAM_HOLDER.set(param); } public static Integer get() { return PARAM_HOLDER.get(); } public static void remove() { PARAM_HOLDER.remove(); } }
2. 修改所有调用方代码,透传参数
public class A { // 注入Spring托管的Ent实例 @Autowired private Ent ent; public void shouldDoSthAndCallMethodGetSth(Integer a) { CallerParamHolder.set(a); try { ent.getSth(); } finally { // 必须在finally中清除,避免线程复用导致参数串读 CallerParamHolder.remove(); } } }
3. 切面中获取参数
@Aspect @Component public class GettingSthAdvisor { @Around("execution(* com.example.demo.aspects.Ent.getSth())") public Object around(ProceedingJoinPoint pjp) throws Throwable { Integer callerParam = CallerParamHolder.get(); // 你的参数处理逻辑 return pjp.proceed(); } }
内容的提问来源于stack exchange,提问作者George
相关产品推荐
相关产品推荐

