Case:接口实现类的方法上使用AspectJ方式实现aop的异常问题
2017-07-30 10:29
716 查看
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动态代理的实现原理以后再写)
相关文章推荐
- 使用注解方式实现Dubbo搭建,解决消费者调用接口出现空指针异常以及事务等问题
- 使用AspectJ提供的注解方式实现aop
- 使用Spring的AOP实现接口方法执行时间记录
- 使用Spring3.0的AOP结合log4j实现接口方法执行时间记录
- spingmvc 接口中方法参数为中文乱码问题 ,使用put方式提交乱码
- 使用继承或接口实现模板方法的方式与函数回调的感悟
- spring AOP (使用AspectJ的xml方式 的aop实现) (7)
- spring cglib使用aop:aspectj-autoproxy的异常问题及解决
- Spring AOP 使用注解的方式实现用户日志的两种方法
- spring 4.0 AOP (使用AspectJ的注解方式 的aop实现)简单实例
- spring 4.0 AOP (使用AspectJ的注解方式 的aop实现)简单实例
- 使用AspectJ提供的注解方式实现aop
- Redis总结(五)缓存雪崩和缓存穿透等问题 Web API系列(三)统一异常处理 C#总结(一)AutoResetEvent的使用介绍(用AutoResetEvent实现同步) C#总结(二)事件Event 介绍总结 C#总结(三)DataGridView增加全选列 Web API系列(二)接口安全和参数校验 RabbitMQ学习系列(六): RabbitMQ 高可用集群
- Spring系列之 (九):AOP实现方式(一):使用AspectJ的xml方式
- spring AOP (使用AspectJ的注解方式 的aop实现) (6)
- Spring系列之 (十):AOP实现方式(二):使用AspectJ的注解方式
- spring 4.0 AOP (使用AspectJ的注解方式 的aop实现)简单实例
- webservice接口常见问题1:客户端使用SOAP方式调用CXF服务时异常
- 继承类或实现接口时对原有方法覆盖时异常抛出声明的规则
- 山寨AjaxPro,解决分布式问题,实现主流接口,保留原版的API方法,唯一的不同是稍微修改下webconfig