Spring反射:如何从代理方法获取原始方法?
解决CGLIB代理后获取原始方法注解的问题
这确实是CGLIB代理时常见的头疼问题——它会生成类似CGLIB$myMethod$n的代理方法,而原始方法的注解并不会自动继承到这些代理方法上,所以你直接在代理方法上找@MyAnnotation肯定拿不到。下面给你几个实用的解决方案:
1. 在CGLIB拦截器中直接用MethodProxy获取原始方法
如果你是在实现MethodInterceptor(CGLIB的回调接口)时处理方法,这是最直接的方式。MethodProxy参数内置了原始方法的引用,直接调用它的getOriginalMethod()就能拿到原始方法,接着就能获取注解了:
public Object intercept(Object proxyObj, Method proxyMethod, Object[] args, MethodProxy methodProxy) throws Throwable { // 获取原始方法 Method originalMethod = methodProxy.getOriginalMethod(); MyAnnotation annotation = originalMethod.getAnnotation(MyAnnotation.class); // 这里可以处理注解逻辑 if (annotation != null) { // do something } return methodProxy.invokeSuper(proxyObj, args); }
2. 通过方法签名匹配原始类中的对应方法
如果是在拦截器外部(比如遍历代理类的方法列表时),可以利用CGLIB代理方法的签名和原始方法完全一致的特点,先拿到原始类(代理类的父类),再通过方法名+参数类型匹配找到原始方法:
// 假设你已经拿到了代理对象 Object proxyInstance = ...; Class<?> originalClass = proxyInstance.getClass().getSuperclass(); for (Method proxyMethod : proxyInstance.getClass().getDeclaredMethods()) { // 筛选出CGLIB生成的目标方法代理 if (proxyMethod.getName().contains("$myMethod$")) { // 提取原始方法名(分割$符号,注意转义) String originalMethodName = proxyMethod.getName().split("\\$")[1]; try { // 根据方法名和参数类型获取原始方法 Method originalMethod = originalClass.getMethod(originalMethodName, proxyMethod.getParameterTypes()); MyAnnotation annotation = originalMethod.getAnnotation(MyAnnotation.class); if (annotation != null) { // 找到带注解的原始方法,处理逻辑 break; } } catch (NoSuchMethodException e) { // 处理异常,比如方法不存在的情况 e.printStackTrace(); } } }
注意:这里用split("\\$")是因为$是正则表达式的特殊字符,必须转义才能正确分割。
3. 借助Spring工具类(Spring环境下)
如果你的项目基于Spring,可以直接用Spring AOP提供的工具类AopUtils,它能帮你快速定位到被代理的原始方法:
import org.springframework.aop.support.AopUtils; // proxyMethod是你拿到的CGLIB代理方法,targetClass是原始类的Class对象 Method originalMethod = AopUtils.getMostSpecificMethod(proxyMethod, targetClass); MyAnnotation annotation = originalMethod.getAnnotation(MyAnnotation.class);
这个方法会自动处理代理层级,帮你找到最具体的原始方法,非常省心。
补充说明
为什么你之前的判断拿不到注解?因为CGLIB生成的代理方法是全新的方法,Java的方法注解默认不会被继承(除非注解本身标注了@Inherited,但这对方法注解无效,@Inherited只作用于类注解),所以必须拿到原始方法才能获取到上面的注解。
内容的提问来源于stack exchange,提问作者Vojtěch
相关产品推荐
相关产品推荐

