You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring AOP技术问题:如何提取方法与参数注解?

问题分析与解决方案

嘿,我一眼就看出问题出在哪了——你用了接口+实现类的结构,当前切面里拿到的方法签名是接口Service里的execute方法,不是你加了@P注解的ServiceImpl实现类方法!让我一步步拆解并解决这个问题:

你的现有代码整理

注解定义

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface MethodAnno {
    Foo[] foo();
}

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface P {
    Bar value();
}

切面代码

@Aspect
@Component
public class MyAspect {
    @Before("@annotation(methodAnnotation)")
    public void methodsWithMethodLevelAnnotation(final JoinPoint pjp, MethodAnno methodAnnotation) {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Annotation[][] parameterAnnotations = signature.getMethod().getParameterAnnotations();
        // parameterAnnotations 始终是单元素数组,且元素是空数组
    }
}

使用示例

public interface Service {
    public void execute(String input);
}

@Service
public class ServiceImpl implements Service {
    @Override
    @MethodAnno
    public void execute(@P String input) {
        // ... 业务逻辑
    }
}

为什么拿不到参数注解?

因为你用了接口+实现类的结构,Spring默认使用JDK动态代理创建代理对象。此时pjp.getSignature()返回的是接口Service中execute方法的签名,而你的@P注解是加在ServiceImpl实现类的方法参数上的——接口方法的参数并没有标注这个注解,所以自然拿不到任何参数注解数据。

解决方法:获取实现类的方法元数据

我们需要从JoinPoint中拿到目标对象(真实的ServiceImpl实例),然后找到对应的实现类方法,再从中提取参数注解。修改后的切面代码如下:

@Aspect
@Component
public class MyAspect {
    @Before("@annotation(methodAnnotation)")
    public void methodsWithMethodLevelAnnotation(final JoinPoint pjp, MethodAnno methodAnnotation) {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        // 1. 获取目标对象的Class
        Class<?> targetClass = pjp.getTarget().getClass();
        // 2. 获取接口方法的方法名和参数类型
        String methodName = signature.getName();
        Class<?>[] parameterTypes = signature.getParameterTypes();
        
        try {
            // 3. 找到实现类中对应的方法
            Method targetMethod = targetClass.getMethod(methodName, parameterTypes);
            // 4. 提取实现类方法的参数注解
            Annotation[][] parameterAnnotations = targetMethod.getParameterAnnotations();
            
            // 5. 遍历处理参数注解
            for (int i = 0; i < parameterAnnotations.length; i++) {
                Annotation[] annotations = parameterAnnotations[i];
                for (Annotation annotation : annotations) {
                    if (annotation instanceof P) {
                        P pAnnotation = (P) annotation;
                        // 这里可以处理你的@P注解逻辑,比如获取Bar值
                        System.out.println("找到@P注解,Bar值:" + pAnnotation.value());
                    }
                }
            }
        } catch (NoSuchMethodException e) {
            // 处理找不到方法的异常,比如日志记录
            e.printStackTrace();
        }
    }
}

额外提示

如果你的项目允许使用CGLIB代理(比如没有实现接口,或者配置Spring强制使用CGLIB),也可以通过修改代理模式来简化操作,但上面的方法是通用的,不管是JDK还是CGLIB代理都能正常工作。

内容的提问来源于stack exchange,提问作者citress

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:13:50