zoukankan      html  css  js  c++  java
  • 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

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    java performance
    C# and Java: Comparing Programming Languages
    MYSQL blogs and articles
    网络基本功系列:细说网络那些事儿
    Spark 优化器 ML的论文
    逻辑回归
    MapReduce
    Spark
    Set-Theory-and-Logic
    k-means
  • 原文地址:https://www.cnblogs.com/chenxingyang/p/15559346.html
Copyright © 2011-2022 走看看