Spring系列之AOP分析之对目标对象的拦截过程(八)-阿里云开发者社区

开发者社区> 木叶_之荣> 正文

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类图如下:
ReflectiveMethodInvocation
MethodInterceptorChain
MethodInterceptorChain
OK,我们在proceed()这个方法中看到了AOP对于目标方法的一个拦截的过程,其中很重要的一个点是调用MethodInterceptor的invoke方法。我们先看一下MethodInterceptor的主要UML类图(由于我们在开发中使用AspectJ注解的方式越来越多,所以我们这里说的基本上都是基于AspectJ注解的):
MethodInterceptor
从上图我们也可以看到不同的通知其实相当于不同的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 源码分析——创建代理对象
1.简介 与筛选合适的通知器相比,创建代理对象的过程则要简单不少,本文所分析的源码不过100行,相对比较简单。在接下里的章节中,我将会首先向大家介绍一些背景知识,然后再去分析源码。
996 0
SpringBoot-13-插曲之Node文件重命名+自动生成json对象
遇到的问题:图片太多,使用起来挺麻烦 [1]有很多图片放服务器里,怎么能更好的管理,更方便拿到图片呢? [2]想用json 以一个对象数组的形式保存这些图片:以[{img:"图片名"},{img:"图片名"}....]形式 [3]虽说想法是很好,但不可能一条一条自己写吧,好歹咱也是21世纪敲代码的人。
829 0
spring mvc 传递对象 二
springController: [java] view plaincopy @Controller   @RequestMapping("/user")   public UserController extends BaseController{       @RequestMapping("/addUser")
1079 0
UML面向对象分析与建模-【6】状态图
一、概述 在一般的面向对象技术中,状态图又称为状态迁移图。描述了一个特定对象的所有可能状态以及由于各种事件的发生而引起的状态之间的迁移。大多数面向对象技术都使用状态图来描述一个对象在其生命周期中的行为。
652 0
Spring cloud Feign不支持对象传参解决办法[完美解决]
Spring cloud Feign不支持对象传参解决办法[完美解决] spring cloud 使用 Feign 进行服务调用时,不支持对象参数。 通常解决方法是,要么把对象每一个参数平行展开,并使用 @RequestParam 标识出每一个参数,要么用 @RequestBody 将请求改为 body 传参,虽然这样解决了问题,但是这样限制了传参方式,并且使代码变得很繁重。
1719 0
晚绑定场景下对象属性赋值和取值可以不需要Pro“.NET技术”pertyInfo
  在《一句代码实现批量数据绑定》中,我通过界面控件ID与作为数据源的实体属性名之间的映射实现了批量数据绑定。由于里面频繁涉及对属性的反射——通过反射从实体对象中获取某个属性值;通过反射为控件的某个属性赋值,所以这不是一种高效的操作方式。
625 0
关于 OpenGL 中平移矩阵变换与实体对象坐标平移的关系分析结论
关于 OpenGL 中平移矩阵变换与实体对象坐标平移的关系分析结论 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循“署名-非商业用途-保持一致”创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS、Android、Html5、Arduino、pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作。
643 0
UML面向对象分析与建模-【5】交互图
一、概述 交互图是用来表达系统的各个对象之间如何交互,如何合作完成某个行为的动态模型工具,它与用例图、状态图、活动图等共同构成了系统的行为视图。 交互图主要用于对用例图中的控制流进行建模,它包括序列图和协作图,其中,序列图按时间次序描述系统中各对象如何通过消息交互,协作图从空间上描述收发消息的对象的结构关系。
832 0
GraphScope 图分析引擎 - GRAPE 介绍
GraphScope 中的图分析引擎继承自 GRAPE,该系统实现了论文 Parallelizing Sequential Graph Computations 中提出的不动点计算模型
240 0
基于对象存储 OSS 的智能数据分析处理框架和功能
今年参加了 2019 全球闪存峰会(Flash Memory World),分享了“基于云存储的智能数据分析处理架构”,重点介绍在对象存储 OSS 之上的数据处理功能,现整理相关内容和大家探讨。
2129 0
153
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载