SpringAOP[5]-MethodInvocation(拦截器的调用)

2021/11/16 6:09:48

本文主要是介绍SpringAOP[5]-MethodInvocation(拦截器的调用),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

原文:SpringAOP联盟(5)-MethodInvocation(拦截器的调用) - 简书 (jianshu.com)

在上文中,代理对象创建后,最终的拦截工作都是交给了MethodInvocation。JDK交给了ReflectiveMethodInvocation,而CGLIB交给CglibMethodInvocation

此处所说的MethodInvocation是AOP联盟包下的,也就是org.aopalliance.intercept.MethodInvocation

此接口会继承Joinpoint接口,注意不要和org.aspectj.lang.JoinPoint搞混。

  1. org.aspectj.lang.JoinPoint:该对象封装了SpringAop中切面方法信息,在切面方法添加JoinPoint参数,可以很方便的获取更多信息。(一般用于@Aspect标注的切面方法入参)。
  2. org.aopalliance.intercept.Joinpoint是AOP联盟中的类,关系如下图所示:
//此接口表示运行时的连接点(AOP术语)
public interface Joinpoint {
    //执行此拦截点,并进入下一个连接点
    Object proceed() throws Throwable;
    //保存当前连接点静态对象,这里一般指的是target
    Object getThis();
    //返回此静态连接点,一般就为当前的Method
    AccessibleObject getStaticPart();
}
public interface Invocation extends Joinpoint {
    //获取参数,例如方法的参数
    Object[] getArguments();
}
// 方法调用时,对这部分进行描述
public interface MethodInvocation extends Invocation {
    // 返回正在被调用得方法,返回的是当前Method对象。
    // 此时,效果同父类的AccessibleObject getStaticPart() 这个方法
    Method getMethod();
}

MethodInvocation作为aopalliance里提供的最底层的接口。Spring也提供了相关的实现。

 

Spring也提供了一个接口proxyMethodInvoation来进行扩展使用。
public interface ProxyMethodInvocation extends MethodInvocation {
    //返回代理对象
    Object getProxy();

    //clone一个,使用的是Object的clone方法
    MethodInvocation invocableClone();
    MethodInvocation invocableClone(Object... arguments);
    //设置参数 增强器、通知执行的时候可能会使用到
    void setArguments(Object... arguments);
    //添加一些kv,但这些kv并不会用于AOP框架,而是保存起来给特殊的拦截器使用
    void setUserAttribute(String key, @Nullable Object value);
    @Nullable
    Object getUserAttribute(String key);
}

 

1. ReflectiveMethodInvocation

Spring提供的实现类:org.springframework.aop.framework.ReflectiveMethodInvocation

该类作为实现类,会实现包含父父类所有的抽象方法。
他也是JdkDynamicAopProxy最终要new出来的类。

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
protected final Object proxy; // 代理对象
    @Nullable
    protected final Object target; // 目标对象
    protected final Method method; // 被拦截的方法

    protected Object[] arguments = new Object[0];
    @Nullable
    private final Class<?> targetClass;

    @Nullable
    private Map<String, Object> userAttributes;
    protected final List<?> interceptorsAndDynamicMethodMatchers;
    
    // currentInterceptorIndex初始值为 -1(拦截链初始值为-1)
    private int currentInterceptorIndex = -1;

    //Spring内部使用的类
    protected ReflectiveMethodInvocation(
            Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
            @Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {

        this.proxy = proxy;
        this.target = target;
        this.targetClass = targetClass;
        // 找到桥接方法,作为最后执行的方法。
        this.method = BridgeMethodResolver.findBridgedMethod(method);
        // 对参数进行适配
        this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
        this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
    }

    @Override
    public final Object getProxy() {
        return this.proxy;
    }
    @Override
    @Nullable
    public final Object getThis() {
        return this.target;
    }
    // 此处:getStaticPart返回的就是当前得method
    @Override
    public final AccessibleObject getStaticPart() {
        return this.method;
    }
    // 注意:这里返回的可能是桥接方法哦
    @Override
    public final Method getMethod() {
        return this.method;
    }
    @Override
    public final Object[] getArguments() {
        return this.arguments;
    }
    @Override
    public void setArguments(Object... arguments) {
        this.arguments = arguments;
    }


    //这里是执行的核心,要执行方法,执行通知都是在此处搞定的。
    //这里是递归调用的方式,执行所有的过滤器链
    @Override
    @Nullable
    public Object proceed() throws Throwable {
        //  currentInterceptorIndex初始值为 -1  如果执行到链条的末尾 则直接调用连接点方法 即 直接调用目标方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            // 这个方法相当于调用了目标方法~~~下面会分析
            return invokeJoinpoint();
        }

        // 获取集合中的 MethodInterceptor(并且currentInterceptorIndex + 1了哦)
        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

        //InterceptorAndDynamicMethodMatcher它是Spring内部使用的一个类。很简单,就是把MethodInterceptor实例和MethodMatcher放在了一起。看看在advisor chain里面是否能够匹配上
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            
            // 去匹配这个拦截器是否适用于这个目标方法  试用就执行拦截器得invoke方法
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            }
            else {
                // 如果不匹配。就跳过此拦截器,而继续执行下一个拦截器
                // 注意:这里是递归调用  并不是循环调用
                return proceed();
            }
        }
        else {
            // 直接执行此拦截器。说明之前已经匹配好了,只有匹配上的方法才会被拦截进来的
            // 这里传入this就是传入了ReflectiveMethodInvocation,从而形成了一个链条了
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }
    /**
     **  AopUtils.invokeJoinpointUsingReflection源码:
     **  ReflectionUtils.makeAccessible(method);
     **    return method.invoke(target, args);
     **/
    //方法调用时简单的`method.invoke(target, args);`。
    //子类可以复写该方法,比如唯一子类`CglibAopProxy`内部类`CglibMethodInvocation`就复写了这个方法(后续有介绍)
    @Nullable
    protected Object invokeJoinpoint() throws Throwable {
        //此处传入的是target,而不能是proxy。否则会进入死循环
        return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
    }
}

 

2. CglibMethodInvocation

它是ReflectiveMethodInvocation的唯一子类,是Cglib自己使用的执行器。你可以将其看做为工厂模式,它会实现一些Cglib特有的方法。
并且CglibMethodInvocationCglibAopProxy的静态内部类。
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {  
  
    @Nullable  
    private final MethodProxy methodProxy;  
  
    public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method,  
            Object[] arguments, @Nullable Class<?> targetClass,  
            List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {  
  
        super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);  
         //做出了特殊处理,methodProxy是子类特有的参数,表示被CGLIB拦截的时候的类
        //MethodProxy:为生成代理类对方法的代理引用,使用MethodProxy比直接调用JDK本身的Method直接执行方法效率会有提升。
        //MethodProxy有两个重要的方法:invoke和invokeSuper。
       //method.getDeclaringClass用来判断当前这个方法是哪个类的方法。
       //若该方法是public方法 且 method不是Object类的方法  且 method不是equals 且 method不是 hashCode 且 method不是toString方法,返回methodProxy对象。
        this.methodProxy = (Modifier.isPublic(method.getModifiers()) &&  
                method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&  
                !AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ?  
                methodProxy : null);  
    }  
  
    @Override  
    protected Object invokeJoinpoint() throws Throwable {  
        if (this.methodProxy != null) {  
            //如果符合上述条件,调用methodProxy去执行目标方法。(使用FastClass调用)
            return this.methodProxy.invoke(this.target, this.arguments);  
        }  
        else {  
            return super.invokeJoinpoint();  
        }  
    }  
}  
那些@AspectJ定义的通知(增强器),或者自己实现的MethodBeforeAdvice、AfterReturningAdvice...最终都会被包装为一个org.aopalliance.intercept.MethodInterceptor,交由MethodInvocation(其子类是ReflectiveMethodInvocation)去执行,它会将该方法上的拦截器链缓存,并递归调用执行。

推荐阅读

https://blog.csdn.net/f641385712/article/details/88975543



这篇关于SpringAOP[5]-MethodInvocation(拦截器的调用)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程