Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Spring源码解析之AOP 中对拦截器调用的实现

Spring源码解析之AOP 中对拦截器调用的实现

作者头像
I Teach You 我教你
发布于 2023-07-18 10:02:37
发布于 2023-07-18 10:02:37
20600
代码可运行
举报
运行总次数:0
代码可运行

前面我们分析了 Spring AOP 实现中得到 Proxy 对象的过程,下面我们看看在 Spring AOP 中拦截器链是怎样被调用的,也就是 Proxy 模式是怎样起作用的,或者说 Spring 是怎样为我们提供 AOP 功能的;在 JdkDynamicAopProxy 中生成 Proxy 对象的时候:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 

这里的 this 参数对应的是 InvocationHandler 对象,这里我们的 JdkDynamicAopProxy 实现了这个接口,也就是说当 Proxy 对象的函数被调用的时候,这个 InvocationHandler 的 invoke 方法会被作为回调函数调用,下面我们看看这个方法的实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
 2    MethodInvocation invocation = null; 
 3    Object oldProxy = null; 
 4    boolean setProxyContext = false; 
 5
 6    TargetSource targetSource = this.advised.targetSource; 
 7    Class targetClass = null; 
 8    Object target = null; 
 9
10    try { 
11        // Try special rules for equals() method and implementation of the 
12        // Advised AOP configuration interface. 
13
14        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { 
15            // What if equals throws exception!? 
16            // This class implements the equals(Object) method itself. 
17            return equals(args[0]) ? Boolean.TRUE : Boolean.FALSE; 
18        } 
19        if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { 
20            // This class implements the hashCode() method itself. 
21            return new Integer(hashCode()); 
22        } 
23        if (Advised.class == method.getDeclaringClass()) { 
24            // service invocations on ProxyConfig with the proxy config 
25            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); 
26        } 
27
28        Object retVal = null; 
29
30        if (this.advised.exposeProxy) { 
31            // make invocation available if necessary 
32            oldProxy = AopContext.setCurrentProxy(proxy); 
33            setProxyContext = true; 
34        } 
35
36        // May be <code>null</code>. Get as late as possible to minimize the time we "own" the target, 
37        // in case it comes from a pool. 
38        // 这里是得到目标对象的地方,当然这个目标对象可能来自于一个实例池或者是一个简单的 JAVA 对象 
39        target = targetSource.getTarget(); 
40        if (target != null) { 
41            targetClass = target.getClass(); 
42        } 
43
44        // get the interception chain for this method 
45        // 这里获得定义好的拦截器链 
46        List chain = this.advised.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this.advised, proxy, method, targetClass); 
47
48        // Check whether we have any advice. If we don't, we can fallback on direct 
49        // reflective invocation of the target, and avoid creating a MethodInvocation. 
50        // 如果没有设定拦截器,那么我们就直接调用目标的对应方法 
51        if (chain.isEmpty()) { 
52            // We can skip creating a MethodInvocation: just invoke the target directly 
53            // Note that the final invoker must be an InvokerInterceptor so we know it does 
54            // nothing but a reflective operation on the target, and no hot swapping or fancy proxying 
55            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args); 
56        } else { 
57            // We need to create a method invocation... 
58            // invocation = advised.getMethodInvocationFactory().getMethodInvocation( 
59            // proxy, method, targetClass, target, args, chain, advised); 
60            // 如果有拦截器的设定,那么需要调用拦截器之后才调用目标对象的相应方法 
61            // 这里通过构造一个 ReflectiveMethodInvocation 来实现,下面我们会看这个 ReflectiveMethodInvocation 类 
62            invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); 
63
64            // proceed to the joinpoint through the interceptor chain 
65            // 这里通过 ReflectiveMethodInvocation 来调用拦截器链和相应的目标方法 
66            retVal = invocation.proceed(); 
67        } 
68
69        // massage return value if necessary 
70        if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy)) { 
71            // Special case: it returned "this" and the return type of the method is type-compatible 
72            // Note that we can't help if the target sets 
73            // a reference to itself in another returned object. 
74            retVal = proxy; 
75        } 
76        return retVal; 
77    } finally { 
78        if (target != null && !targetSource.isStatic()) { 
79            // must have come from TargetSource 
80            targetSource.releaseTarget(target); 
81        } 
82
83        if (setProxyContext) { 
84            // restore old proxy 
85            AopContext.setCurrentProxy(oldProxy); 
86        } 
87    } 
88} 

我们先看看目标对象方法的调用,这里是通过 AopUtils 的方法调用 - 使用反射机制来对目标对象的方法进行调用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args) throws Throwable { 
 2
 3    // Use reflection to invoke the method. 
 4    // 利用放射机制得到相应的方法,并且调用 invoke 
 5    try { 
 6        if (!Modifier.isPublic(method.getModifiers()) || 
 7            !Modifier.isPublic(method.getDeclaringClass().getModifiers())) { 
 8                method.setAccessible(true); 
 9        } 
10        return method.invoke(target, args); 
11    } catch (InvocationTargetException ex) { 
12        // Invoked method threw a checked exception. 
13        // We must rethrow it. The client won't see the interceptor. 
14        throw ex.getTargetException(); 
15    } catch (IllegalArgumentException ex) { 
16        throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" + method + "] on target [" + target + "]", ex); 
17    } catch (IllegalAccessException ex) { 
18        throw new AopInvocationException("Couldn't access method: " + method, ex); 
19    } 
20} 

对拦截器链的调用处理是在 ReflectiveMethodInvocation 里实现的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1public Object proceed() throws Throwable { 
 2    // We start with an index of -1 and increment early. 
 3    // 这里直接调用目标对象的方法,没有拦截器的调用或者拦截器已经调用完了,这个 currentInterceptorIndex 的初始值是 0 
 4    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size()) { 
 5        return invokeJoinpoint(); 
 6    } 
 7
 8    Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(this.currentInterceptorIndex); 
 9    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { 
10        // Evaluate dynamic method matcher here: static part will already have 
11        // been evaluated and found to match. 
12        // 这里获得相应的拦截器,如果拦截器可以匹配的上的话,那就调用拦截器的 invoke 方法 
13        InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; 
14        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { 
15            return dm.interceptor.invoke(nextInvocation()); 
16        } else { 
17            // Dynamic matching failed. 
18            // Skip this interceptor and invoke the next in the chain. 
19            // 如果拦截器匹配不上,那就调用下一个拦截器,这个时候拦截器链的位置指示后移并迭代调用当前的 proceed 方法 
20            this.currentInterceptorIndex++; 
21            return proceed(); 
22        } 
23    } 
24    else { 
25        // It's an interceptor, so we just invoke it: The pointcut will have 
26        // been evaluated statically before this object was constructed. 
27        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(nextInvocation()); 
28    } 
29} 

这里把当前的拦截器链以及在拦截器链的位置标志都 clone 到一个 MethodInvocation 对象了,作用是当前的拦截器执行完之后,会继续沿着得到这个拦截器链执行下面的拦截行为,也就是会迭代的调用上面这个 proceed:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1private ReflectiveMethodInvocation nextInvocation() throws CloneNotSupportedException { 
2    ReflectiveMethodInvocation invocation = (ReflectiveMethodInvocation) clone(); 
3    invocation.currentInterceptorIndex = this.currentInterceptorIndex + 1; 
4    invocation.parent = this; 
5    return invocation; 
6} 

这里的 nextInvocation 就已经包含了当前的拦截链的基本信息,我们看到在 Interceptor 中的实现比如 TransactionInterceptor 的实现中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1public Object invoke(final MethodInvocation invocation) throws Throwable { 
 2    ...//这里是 TransactionInterceptor 插入的事务处理代码,我们会在后面分析事务处理实现的时候进行分析 
 3        try { 
 4            //这里是对配置的拦截器链进行迭代处理的调用 
 5            retVal = invocation.proceed(); 
 6        } 
 7    ...//省略了和事务处理的异常处理代码 ,也是 TransactionInterceptor 插入的处理 
 8    else { 
 9        try { 
10            Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager.execute(txAttr, new TransactionCallback() { 
11                public Object doInTransaction(TransactionStatus status) { 
12                    //这里是 TransactionInterceptor 插入对事务处理的代码 
13                    TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status); 
14                    //这里是对配置的拦截器链进行迭代处理的调用,接着顺着拦截器进行处理 
15                    try { 
16                        return invocation.proceed(); 
17                    } 
18    ...//省略了和事务处理的异常处理代码 ,也是 TransactionInterceptor 插入的处理 
19} 

从上面的分析我们看到了 Spring AOP 的基本实现,比如 Spring 怎样得到 Proxy,怎样利用 JAVA Proxy 以及反射机制对用户定义的拦截器链进行处理。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/08/05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Spring的JDK动态代理如何实现的(源码解析)
从上面的源码可以看出Spring中的JDKDynamicAopProxy和我们自定一JDK代理是一样的,也是实现了InvocationHandler接口。并且提供了getProxy方法创建代理类,重写了invoke方法(该方法是一个回调方法)。具体看源码
@派大星
2023/06/28
2550
Spring的JDK动态代理如何实现的(源码解析)
spring aop (下)调用拦截链
之前我们说到,当使用jdk动态代理时,会调用该类的getProxy方法生成一个代理对象,返回给外界调用。该类继承了InvocationHandler,所有代理对象的方法调用都会被拦截到该对象的invoke上。
平凡的学生族
2019/06/03
9420
SpringAop源码分析(基于注解)四:拦截器链
本文依据JdkDynamicAopProxy来分析,对CGLIB感兴趣的同学看一看ObjenesisCglibAopProxy相关代码。 JdkDynamicAopProxy实现了InvocationHandler接口,我们来看下invoke()方法:
周同学
2019/10/24
9040
Spring AOP源码学习:一次请求调用全流程
Spring AOP源码学习:一次请求调用全流程
Java架构师必看
2021/06/17
5870
Spring AOP 源码分析 - 拦截器链的执行过程
1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程。现在我们的得到了 bean 的代理对象,且通知也以合适的方式插在了目标方法的前后。接下来要做的事情,就是执行通知逻辑了。通知可能在目标方法前执行,也可能在目标方法后执行。具体的执行时机,取决于用户的配置。当目标方法被多个通知匹配到时,Spring 通过引入拦截器链来保证每个通知的正常执行。在本文中,我们将会通过源码了解到
田小波
2018/07/04
1.5K0
Spring AOP分析(2) -- JdkDynamicAopProxy实现AOP
YGingko
2017/12/28
1.5K0
Spring AOP 创建代理的源码解析
在上篇文章 Spring AOP 注解方式源码解析 中已经获取到了 bean 的对应增强器,之后,就可以创建对应的代理了,Spring AOP 底层使用的是 JDK 动态代理和 CGLIB 的代理,在什么情况下使用JDK动态代理,什么时候使用 CGLIB 代理呢,下面通过源码来看一下.
Java技术编程
2020/05/20
1.2K0
从Spring源码探究AOP代码织入的过程
AOP是OOP的延续,是Aspect Oriented Programming 的缩写,意思是面向切面编程。
向着百万年薪努力的小赵
2022/12/02
4450
从Spring源码探究AOP代码织入的过程
Spring源码解析(九):AOP源码之@Aspect所有相关注解解析
InstantiationModelAwarePointcutAdvisorImpl构造函数 创建具体通知
冬天vs不冷
2025/01/21
2790
Spring源码解析(九):AOP源码之@Aspect所有相关注解解析
Spring AOP实现原理简介[通俗易懂]
AOP联盟将AOP体系分为三层,从三层结构可以看出,AOP实现方式有很多种,包括反射、元数据处理、程序处理、拦截器处理等,通过本节学习,你就会看到Spring AOP的实现使用的是Java语言本身的特性,即Java Proxy代理类、拦截器技术实现。
全栈程序员站长
2022/09/22
4330
Spring AOP实现原理简介[通俗易懂]
Spring AOP高级——源码实现(3)AopProxy代理对象之JDK动态代理的创建过程
spring-aop-4.3.7.RELEASE    在《Spring AOP高级——源码实现(1)动态代理技术》中介绍了两种动态代理技术,当然在Spring AOP中代理对象的生成也是运用的这两种技术。本文将介绍Spring AOP如何通过JDK动态代理的方式创建代理对象。   JDK动态代理以及CGLIB代理这两种生成代理对象的方式在Spring AOP中分别对应两个类:JdkDynamicAopProxy和CglibAopProxy,而AopProxy是这两个类的父接口。   AopProxy接口中
用户1148394
2018/01/09
1.2K0
【10】Spring源码-分析篇-AOP源码分析
  本文我们开始讲解Spring中的AOP原理和源码,我们前面手写了AOP的实现,了解和自己实现AOP应该要具备的内容,我们先回顾下,这对我们理解Spring的AOP是非常有帮助的。
用户4919348
2022/10/28
8440
【10】Spring源码-分析篇-AOP源码分析
《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://louluan.blog.csdn.net/article/details/51155821
亦山
2019/05/25
5200
Spring AOP原理分析一次看懂
什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于
Tanyboye
2018/07/02
5580
深入理解Spring框架之AOP实现原理
该动态代理是基于接口的动态代理,所以并没有一个原始方法的调用过程,整个方法都是被拦截的。
JavaQ
2019/05/15
2.2K0
深入理解Spring框架之AOP实现原理
AOP执行流程
之前跟大家聊IOC的时候跟大家聊过它的启动过程,同样的AOP也有指定的执行流程,但是需要IOC作为基础。
Vincent-yuan
2021/12/16
3340
AOP执行流程
Spring中AOP相关的API及源码解析,原来AOP是这样子的
之所以写这么一篇文章主要是因为下篇文章将结束Spring启动整个流程的分析,从解析配置到创建对象再到属性注入最后再将创建好的对象初始化成为一个真正意义上的Bean。因为下篇文章会涉及到AOP,所以提前单独将AOP的相关API及源码做一次解读,这样可以降低阅读源码的障碍,话不多说,我们进入正文!
程序员DMZ
2020/07/20
8460
Spring中AOP相关的API及源码解析,原来AOP是这样子的
Spring事务源码解析
2.1.4. TransactionManagementConfigurationSelector
爱撒谎的男孩
2019/12/31
1.3K0
Spring是如何实现AOP的
在AbstractAutoProxyCreator中存在以下两个方法,一个是对应循环依赖中如何提前暴露Bean的引用地址,另一个则是根据Bean实例获取最终Bean的后置处理器中,二者都调用了一个方法:wrapIfNecessary,这就是AOP的入口,前者对应开发者在注入单例bean时获取到代理对象(例如Service层注入其他Service得到的是其代理对象),后置则对应普通流程的增强类方法。
默 语
2024/11/22
810
关于Spring AOP,除了动态代理、CGLIB,你还知道什么?
Spring 作为 Java 中最流行的框架,主要归功于其提供的 IOC 和 AOP 功能。本文将讨论 Spring AOP 的实现。第一节将介绍 AOP 的相关概念,若熟悉可跳过,第二节中结合源码介绍 Spring 是如何实现 AOP 的各概念。
草捏子
2020/08/10
5490
关于Spring AOP,除了动态代理、CGLIB,你还知道什么?
推荐阅读
相关推荐
Spring的JDK动态代理如何实现的(源码解析)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验