Case:接口实现类的方法上使用AspectJ方式实现aop的异常问题

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动态代理的实现原理以后再写)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值