美文网首页深度解析Spring5源码
38--SpringAop代理调用过程(二)

38--SpringAop代理调用过程(二)

作者: 闲来也无事 | 来源:发表于2018-12-20 19:46 被阅读13次

    接前面一章继续分析SpringAOP获取拦截器链和拦截器链的调用过程。

    1.获取拦截器链
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
        MethodCacheKey cacheKey = new MethodCacheKey(method);
        List<Object> cached = this.methodCache.get(cacheKey);
        if (cached == null) {
            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
            this.methodCache.put(cacheKey, cached);
        }
        return cached;
    }
    
    /**
     * 获取拦截器链
     */
    @Override
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {
    
        // This is somewhat tricky... We have to process introductions first,
        // but we need to preserve order in the ultimate list.
        // 获取AdvisorAdapterRegistry对象,Spring默认初始化了MethodBeforeAdviceAdapter,AfterReturningAdviceAdapter和ThrowsAdviceAdapter
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        // 获取所有增强
        Advisor[] advisors = config.getAdvisors();
        // 创建interceptorList保存返回结果,这里可以看到new ArrayList指定了集合长度,也是编码中节约内存开销的一个小技巧
        List<Object> interceptorList = new ArrayList<>(advisors.length);
        // 获取代理类的Class对象
        Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
        Boolean hasIntroductions = null;
    
        // 循环所有的增强
        for (Advisor advisor : advisors) {
            // 如果增强是PointcutAdvisor的实例
            if (advisor instanceof PointcutAdvisor) {
                // Add it conditionally.
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                // config.isPreFiltered() -> 返回是否对该代理配置进行了预筛选,以便仅对其进行筛选包含适用的增强(匹配此代理的目标类)。
                // pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass) -> 当前切点匹配的类是否匹配actualClass
                // 以上两个条件是在类一级别上做出判断,如果符合,则接下来对方法级别的再做匹配判断
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                    // 获取当前切点匹配的方法
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    boolean match;
                    // 区分普通的MethodMatcher和IntroductionAwareMethodMatcher,分别调用不同的匹配方法做出判断
                    // IntroductionAwareMethodMatcher可以作用域引入类型的增强,且当匹配方法不包含引用增强时,可以提升匹配效率
                    if (mm instanceof IntroductionAwareMethodMatcher) {
                        if (hasIntroductions == null) {
                            hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
                        }
                        match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
                    }
                    else {
                        match = mm.matches(method, actualClass);
                    }
                    // 如果匹配
                    if (match) {
                        MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                        if (mm.isRuntime()) {
                            // Creating a new object instance in the getInterceptors() method
                            // isn't a problem as we normally cache created chains.
                            for (MethodInterceptor interceptor : interceptors) {
                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                            }
                        }
                        else {
                            interceptorList.addAll(Arrays.asList(interceptors));
                        }
                    }
                }
            }
            // 如果增强是IntroductionAdvisor实例
            else if (advisor instanceof IntroductionAdvisor) {
                IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
                if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                    Interceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
            // 其他类型
            else {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
    
        return interceptorList;
    }
    

    该段代码比较关键的点:

    // 如果匹配,获取方法拦截器
    if (match) {
        MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
        if (mm.isRuntime()) {
            // Creating a new object instance in the getInterceptors() method
            // isn't a problem as we normally cache created chains.
            for (MethodInterceptor interceptor : interceptors) {
                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
            }
        }
        else {
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }
    

    通过上面的代码可以发现Spring最终还是要把增强(切面)转换为方法拦截器,来看其具体的实现:

    /**
     * 获取方法连接器
     */
    @Override
    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = new ArrayList<>(3);
        Advice advice = advisor.getAdvice();
        // 1.如果增强是MethodInterceptor类型直接添加
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }
        // 2.循环增强适配器,并判断是否支持
        for (AdvisorAdapter adapter : this.adapters) {
            if (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        }
        // 3.返回结果
        return interceptors.toArray(new MethodInterceptor[0]);
    }
    

    通过这段代码,如果增强是MethodInterceptor的实例,直接加入结果中;那么哪些增强是MethodInterceptor类型呢?先不用着急,继续看下面的处理,下面的代码里出现了一个增强适配器,我们来看一下其中都包含了哪些适配器类型:

    private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
    
    public DefaultAdvisorAdapterRegistry() {
        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }
    

    DefaultAdvisorAdapterRegistry通过构造函数对增强适配器进行了初始化,包含了MethodBeforeAdviceAdapter前置增强适配器、AfterReturningAdviceAdapter后置返回增强适配器、ThrowsAdviceAdapter后置异常增强适配器。那么从这里我们也可以推断出,除了这几种增强适配器对应的增强类型之外,其他的都是MethodInterceptor类型。

    接下来看下这三种适配器都做了哪些工作:

    • MethodBeforeAdviceAdapter
    /**
     * 增强适配器
     * 这个方法在获取拦截器链的时候调用,从这里也可以看出,Spring中的advisor(增强/切面)
     * 最终还是被转换为MethodInterceptor对象
     *
     * AdvisorAdapter的实现类有AfterReturningAdviceAdapter,MethodBeforeAdviceAdapter,ThrowsAdviceAdapter三个
     *
     * AfterReturningAdviceAdapter -> new AfterReturningAdviceInterceptor(advice) -> 后置返回增强
     * MethodBeforeAdviceAdapter -> new MethodBeforeAdviceInterceptor(advice) -> 前置增强
     * ThrowsAdviceAdapter -> new ThrowsAdviceInterceptor(advisor.getAdvice()) -> 该适配器有些特殊...看源码吧
     */
    @Override
    public MethodInterceptor getInterceptor(Advisor advisor) {
        MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
        return new MethodBeforeAdviceInterceptor(advice);
    }
    
    • AfterReturningAdviceAdapter
    public MethodInterceptor getInterceptor(Advisor advisor) {
        AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
        return new AfterReturningAdviceInterceptor(advice);
    }
    
    • ThrowsAdviceAdapter
    @Override
    public MethodInterceptor getInterceptor(Advisor advisor) {
        return new ThrowsAdviceInterceptor(advisor.getAdvice());
    }
    

    看到这里大家一定有所了解了,Spring中的增强,最终还是会转换为方法拦截器调用。

    3. 拦截器链调动过程
    /**
     * 调用拦截器链
     *
     * currentInterceptorIndex维护了一个计数器,该计数器从-1开始,当计数器值等于拦截方法长度减一时,
     * 表名所有的增强方法已经被调用(但是不一定被真正执行),那么此时调用连接点的方法,针对本例:即sayHello方法
     */
    @Override
    @Nullable
    public Object proceed() throws Throwable {
        //  We start with an index of -1 and increment early.
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }
    
        Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    
        // 动态匹配增强
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // Evaluate dynamic method matcher here: static part will already have
            // been evaluated and found to match.
            InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
            // 匹配成功则执行
            if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            }
            // 匹配失败则跳过并执行下一个拦截器
            else {
                // Dynamic matching failed.
                // Skip this interceptor and invoke the next in the chain.
                return proceed();
            }
        }
        // 静态增强
        else {
            // It's an interceptor, so we just invoke it: The pointcut will have
            // been evaluated statically before this object was constructed.
            // System.out.println(interceptorOrInterceptionAdvice.getClass());
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }
    

    这段代码看似简单,但是如果真的debug进去,方法栈还是比较深刻的,前面介绍过在获取到合适的增强集合之后,首先在其首位加入了ExposeInvocationInterceptor拦截器,然后对增强集合进行了排序(当然ExposeInvocationInterceptor依然会在首位),那么接下来第一个拦截器调用就是ExposeInvocationInterceptor了。

    1. ExposeInvocationInterceptor
    public Object invoke(MethodInvocation mi) throws Throwable {
        MethodInvocation oldInvocation = invocation.get();
        invocation.set(mi);
        try {
            // 继续拦截器链调用
            return mi.proceed();
        }
        finally {
            invocation.set(oldInvocation);
        }
    }
    
    1. AspectJAfterThrowingAdvice
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            // 继续拦截器链调用
            return mi.proceed();
        }
        catch (Throwable ex) {
            if (shouldInvokeOnThrowing(ex)) {
                invokeAdviceMethod(getJoinPointMatch(), null, ex);
            }
            throw ex;
        }
    }
    
    1. AspectJAfterThrowingAdvice
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            // 继续拦截器链调用
            return mi.proceed();
        }
        catch (Throwable ex) {
            if (shouldInvokeOnThrowing(ex)) {
                invokeAdviceMethod(getJoinPointMatch(), null, ex);
            }
            throw ex;
        }
    }
    
    1. AfterReturningAdviceInterceptor
    public Object invoke(MethodInvocation mi) throws Throwable {
        // 继续拦截器链调用
        Object retVal = mi.proceed();
        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
        return retVal;
    }
    
    1. AspectJAfterAdvice
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            // 继续拦截器链调用
            return mi.proceed();
        }
        finally {
            invokeAdviceMethod(getJoinPointMatch(), null, null);
        }
    }
    
    1. AspectJAroundAdvice
    public Object invoke(MethodInvocation mi) throws Throwable {
        if (!(mi instanceof ProxyMethodInvocation)) {
            throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
        }
        ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
        ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
        JoinPointMatch jpm = getJoinPointMatch(pmi);
        return invokeAdviceMethod(pjp, jpm, null, null);
    }
    

    在这里终于看到了方法的调用:

    protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
        Object[] actualArgs = args;
        if (this.aspectJAdviceMethod.getParameterCount() == 0) {
            actualArgs = null;
        }
        try {
            ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
            // TODO AopUtils.invokeJoinpointUsingReflection
            // 调用代理方法
            return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
        }
        catch (IllegalArgumentException ex) {
            throw new AopInvocationException("Mismatch on arguments to advice method [" +
                    this.aspectJAdviceMethod + "]; pointcut expression [" +
                    this.pointcut.getPointcutExpression() + "]", ex);
        }
        catch (InvocationTargetException ex) {
            throw ex.getTargetException();
      }
    
    public Object invoke(Object obj, Object... args)
            throws IllegalAccessException, IllegalArgumentException,
               InvocationTargetException
    {
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                checkAccess(caller, clazz, obj, modifiers);
            }
        }
        MethodAccessor ma = methodAccessor;             // read volatile
        if (ma == null) {
            ma = acquireMethodAccessor();
        }
        return ma.invoke(obj, args);
    }
    

    代码终于执行到了Method类的invoke方法,接下来就可以调用我们的增强方法了:

    1. MethodBeforeAdviceInterceptor
    @Around("test()")
    public Object aroundTest(ProceedingJoinPoint p) throws Throwable {
        System.out.println("==环绕增强开始");
        // 继续拦截器链调用
        Object o = p.proceed();
        System.out.println("==环绕增强结束");
        return o;
    }
    

    执行完之后,我们发现前置增强还没有被调用进来,继续:

    public Object invoke(MethodInvocation mi) throws Throwable {
        // 调用前置增强
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        return mi.proceed();
    }
    
    1. 目标方法
      执行完前置增强之后,再次进入到proceed方法,这时候,计数器已经满足条件了,执行目标方法调用:
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }
    

    待执行完目标方法调用后,再将之前压入方法栈的那些增强方法依次出栈并调用。这一段的代码调用用文字表述挺困难的,大家自己跟踪代码吧。。。

    到这里拦截器链的调用过程分析就结束了,这里分析的不是那么明确,还是多跟踪代码吧。

    相关文章

      网友评论

        本文标题:38--SpringAop代理调用过程(二)

        本文链接:https://www.haomeiwen.com/subject/wcyukqtx.html