Case:接口实现类的方法上使用AspectJ方式实现aop的异常问题
来源:互联网 发布:施温格 知乎 编辑:程序博客网 时间:2024/05/17 23:10
Case:接口实现类的方法上使用AspectJ方式实现aop的异常问题
现象:
在接口实现类的方法上定义AOP注解,但是在AOP注解执行方法内部无法获取注解类的实例
问题简化如下:
接口:
package reflect;interface TestInterface{ void print();}
接口实现类:
package reflect;class Test implements TestInterface{ public void print() { System.out.println("I am print"); }}
注解类:
@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documented@interface Log{ String value() default "";}
AOP执行方法:
@Around("@annotation(reflect.Log)")public Object process(ProceedingJoinPoint joinPoint) { //根据切入点获取类名、方法名 MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); Method method = methodSignature.getMethod(); String methodName = method.getName(); String className = method.getDeclaringClass().getSimpleName(); //获取注解中的参数 Log log = method.getDeclaredAnnotation(Log.class); String value = log.value(); // 参数操作 ...... Object object = null; try { object = joinPoint.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); } return object;}
在执行到process方法中时,获取到的methodName值是print,className值是TestInterface,method.toString结果是:public abstract void reflect.TestInterface.print(),log值是null。
疑问:预想情况下,log值不应该是null,而是Log注解类的实例;className值应为Test,method执行toString方法的结果应为:public void reflect.Test.print()
分析:
在process方法中断点,观察线程执行堆栈如下:
从上图看到,process方法是被$Proxy75代理类间接调用的,说明AOP底层实现是JDK动态代理。
在JDK动态代理中,程序通过生成实现被代理类接口的代理类达到代理的目的。在生成的代理类中,被代理类方法对应的Method实例是通过被代理类实现的接口获取的。这个Method实例通过方法调用层层传递,在process方法中,被封装到MethodInvvocationProceedingJoinPoint对象的joinPoint实例中。所以在process方法中获取对应参数时才会出现之前奇怪的结果。
jdk动态代理执行流程详见:JDK动态代理执行流程解析
通过以上分析可知,传入process方法的Method实例是TestInterface接口中print方法的Method实例,不是Test实现类的print方法的Method实例,所以在process方法中无法通过调用method.getDeclaredAnnotation方法获取Log注解实例。
解决:
将applicationContext.xml中的
<aop:aspectj-autoproxy />
改成
<aop:aspectj-autoproxy proxy-target-class="true" />
问题解决。
其实质是,在AOP动态代理的实现方式上,使用cglib代理代替jdk动态代理。
(TODO:关于cglib动态代理的实现原理以后再写)
- Case:接口实现类的方法上使用AspectJ方式实现aop的异常问题
- 使用AspectJ提供的注解方式实现aop
- spring 4.0 AOP (使用AspectJ的注解方式 的aop实现)简单实例
- AOP的annotation实现方式是基于AspectJ的实现
- AspectJ注解方式实现AOP
- AOP实现方式2——通过AspectJ提供的注解实现AOP
- AOP实现方式2——通过AspectJ提供的注解实现AOP
- 8.4.1: AspectJ 实现AOP的准备
- Spring 的AOP-AspectJ静态实现
- aspectj实现aop的两种操作
- Spring整合aspectj框架实现的aop
- Spring整合aspectj框架实现的aop
- AspectJ对AOP的实现(xml)
- 使用Spring的AOP实现接口方法执行时间记录
- AOP,AspectJ 实现统一接口耗时统计
- Spring通过@AspectJ方式实现AOP
- AspectJ实现AOP(xml配置方式)
- AspectJ实现AOP(注解方式)
- object-fit
- HDU6053 前缀和+容斥
- 数据库笔记
- ACSII码排序
- java+discuz部署和通信问题总结
- Case:接口实现类的方法上使用AspectJ方式实现aop的异常问题
- 回形取数
- POJ 2226 Muddy Fields 二分图巧妙建图 + 二分图最大匹配
- opencv之Threshold()与AdaptiveThreshold()函数
- 优化MySQL数据库的方法
- CodeForces-232A【构造 二分】
- 如何通过submit提交form表单获取后台传来的返回值
- 不相交集类
- 蛇形填数