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
相关产品推荐
相关产品推荐

