Spring系列之AOP分析之对目标对象的拦截过程

Posted 木叶之荣

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring系列之AOP分析之对目标对象的拦截过程相关的知识,希望对你有一定的参考价值。

我们在上一篇文章中简单的说了调用动态代理对象方法的过程,也说了AOP拦截器执行链的生成过程。我们接着说AOP对目标对象的拦截过程。下面的代码是我们要分析的重点:

//proxy:生成的动态代理对象
//target:目标对象
//method:目标方法
//args:目标方法参数
//targetClass:目标类对象
//chain: AOP拦截器执行链  是一个MethodInterceptor的集合 这个链条的获取过程参考我们上一篇文章的内容
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//开始执行AOP的拦截过程
retVal = invocation.proceed();

//构造ReflectiveMethodInvocation对象
protected ReflectiveMethodInvocation(
            Object proxy, Object target, Method method, Object[] arguments,
            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;
    
    public Object proceed() throws Throwable 
        //  currentInterceptorIndex初始值为 -1 
        // 如果执行到链条的末尾 则直接调用连接点方法 即 直接调用目标方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) 
            //下面会分析
            return invokeJoinpoint();
        
        //获取集合中的 MethodInterceptor
        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        //如果是InterceptorAndDynamicMethodMatcher类型
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) 
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            //这里每一次都去匹配是否适用于这个目标方法
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) 
                //如果匹配则直接调用 MethodInterceptor的invoke方法
                //注意这里传入的参数是this 我们下面看一下 ReflectiveMethodInvocation的类型
                return dm.interceptor.invoke(this);
            
            else 
                //如果不适用于此目标方法  则继续执行下一个链条 
                //递归调用
                return proceed();
            
        
        else 
            //说明是适用于此目标方法的 直接调用 MethodInterceptor的invoke方法  传入this即ReflectiveMethodInvocation实例
            //传入this进入 这样就可以形成一个调用的链条了
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        
    

invokeJoinpoint方法

    protected Object invokeJoinpoint() throws Throwable 
        //this.target 目标对象
        //this.method 目标方法
        this.arguments 目标方法参数信息
        return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
    
    public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
            throws Throwable 

        // Use reflection to invoke the method.
        try 
            //设置方法可见性
            ReflectionUtils.makeAccessible(method);
            //反射调用  最终是通过反射去调用目标方法
            return method.invoke(target, args);
        
        catch (InvocationTargetException ex) 
            // Invoked method threw a checked exception.
            // We must rethrow it. The client won't see the interceptor.
            throw ex.getTargetException();
        
        catch (IllegalArgumentException ex) 
            throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
                    method + "] on target [" + target + "]", ex);
        
        catch (IllegalAccessException ex) 
            throw new AopInvocationException("Could not access method [" + method + "]", ex);
        
    

ReflectiveMethodInvocation的UML类图如下:

MethodInterceptorChain

OK,我们在proceed()这个方法中看到了AOP对于目标方法的一个拦截的过程,其中很重要的一个点是调用MethodInterceptor的invoke方法。我们先看一下MethodInterceptor的主要UML类图(由于我们在开发中使用AspectJ注解的方式越来越多,所以我们这里说的基本上都是基于AspectJ注解的):

从上图我们也可以看到不同的通知其实相当于不同的MethodInterceptor类型。像前置通知会交给:MethodBeforeAdviceInterceptor来进行处理,后置通知是由AspectJAfterAdvice来处理的,环绕通知是由AspectJAroundAdvice来处理的。我们也挑几个通知类型来说一下具体的调用过程。先说一下前置通知:
MethodBeforeAdviceInterceptor

//实现了MethodInterceptor接口
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable 
    //这个对象的获取参考这个方法org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
    //在之前的文章中有说过 不再描述
    //这个MethodBeforeAdvice是AspectJMethodBeforeAdvice实例
    private MethodBeforeAdvice advice;

    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) 
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable 
        //这里就会执行  前置通知的逻辑 这里的advice是 AspectJMethodBeforeAdvice
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
        //这里传入的MethodInvocation是ReflectiveMethodInvocation对象,即前面说的  传入this
        //相当于ReflectiveMethodInvocation.proceed() 递归调用。
        return mi.proceed();
    

AspectJMethodBeforeAdvice#before代码如下:

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable 
        //这里传进来的目标对象、目标参数、目标方法都没有用到
        invokeAdviceMethod(getJoinPointMatch(), null, null);
    
    protected JoinPointMatch getJoinPointMatch() 
        //这里从线程上下文中获取MethodInvocation 看到这里你也许会感到奇怪  跟着文章分析来看 我们没有在设置过上下文的值啊
        //这里是怎么获取到MethodInvocation 的对象的呢?
        //不知道你是否还记得 我们在获取Advisor的时候 调用过这样的一个方法org.springframework.aop.aspectj.AspectJProxyUtils#makeAdvisorChainAspectJCapableIfNecessary
        //在这个方法中会有这样的一段代码 
        // if (foundAspectJAdvice && //!advisors.contains(ExposeInvocationInterceptor.ADVISOR)) 
        //     如果获取到了 Advisor  则向 Advisor集合中添加第一个元素 即 ExposeInvocationInterceptor.ADVISOR
        //也就是说 我们的 Advisor列表中的第一个元素为ExposeInvocationInterceptor.ADVISOR 它是一个DefaultPointcutAdvisor的实例
        // 对于任何的目标方法都返回true  它的Advice是ExposeInvocationInterceptor
        //      advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
        //      return true;
        //  
        // 这样我们就不难理解了,在调用ReflectiveMethodInvocation#proceed的时候第一个调用的MethodInterceptor是ExposeInvocationInterceptor
        //ExposeInvocationInterceptor的invoke方法的内容如下:
        //  public Object invoke(MethodInvocation mi) throws Throwable 
        //   先取出旧的MethodInvocation的值
        //    MethodInvocation oldInvocation = invocation.get();
        //    这里设置新的 MethodInvocation 就是这里了!!!
        //    invocation.set(mi);
        //    try 
        //      递归调用
        //      return mi.proceed();
        ///   
        //   finally 
        //     invocation.set(oldInvocation);
        //   
    //      
        MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
        if (!(mi instanceof ProxyMethodInvocation)) 
            throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
        
        //这里主要是获取 JoinPointMatch
        return getJoinPointMatch((ProxyMethodInvocation) mi);
    

关于invokeAdviceMethod方法的内容我们在下一篇文章中继续分析

以上是关于Spring系列之AOP分析之对目标对象的拦截过程的主要内容,如果未能解决你的问题,请参考以下文章

Spring系列之AOP分析之对通知方法的执行过程

Spring系列之AOP分析之代理对象的创建

Spring系列之AOP分析之为目标类挑选合适的Advisor

Spring Boot AOP之对请求的参数入参与返回结果进行拦截处理

Spring Boot AOP之对请求的参数入参与返回结果进行拦截处理

Spring技术内幕:Spring AOP的实现原理