Spring 源码阅读 72:基于 CGLIB 的 AOP 代理的原理(2)- 拦截器的查找与执行

简介: 【1月更文挑战第7天】本文分析了基于 CGLIB 的 AOP 代理如何查找和执行拦截器链,其主要的逻辑在 DynamicAdvisedInterceptor 的intercept方法执行。


基于 Spring Framework v5.2.6.RELEASE

相关阅读:Spring 源码阅读 60:通过 JDK 动态代理或者 CGLIB 创建 AOP 代理对象

接上一篇:Spring 源码阅读 71:基于 CGLIB 的 AOP 代理的原理(1)- DynamicAdvisedInterceptor 分析

概述

上一篇分析了基于 CGLIB 的 AOP 代理对象执行 AOP 增强逻辑的入口,也就是 DynamicAdvisedInterceptor 的intercept方法,本文来进入这个方法,分析其执行增强逻辑的原理。

DynamicAdvisedInterceptor 的 intercept 方法

首先看这个方法的源码。

方法虽然很长,但是真正执行逻辑的代码并不多。

ObjectoldProxy=null;
booleansetProxyContext=false;
Objecttarget=null;
TargetSourcetargetSource=this.advised.getTargetSource();

方法的一开始会声明一些变量,这些变量会在后面的流程中看到,其中包括从advised属性中获取到的被代理的目标对象。advised成员变量是在创建 DynamicAdvisedInterceptor 是通过构造方法的参数传入的。

后续的流程会进入一个try语句块。

if (this.advised.exposeProxy) {
// Make invocation available if necessary.oldProxy=AopContext.setCurrentProxy(proxy);
setProxyContext=true;
}

这个if语句块中,会将代理对象放到 AopContext 上下文中,不过默认情况下,this.advised.exposeProxy的值是false,因此这里的逻辑不会被执行。

拦截器的查找

// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...target=targetSource.getTarget();
Class<?>targetClass= (target!=null?target.getClass() : null);
List<Object>chain=this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

接下来会进入一个重要的步骤,就是根据目标类型和当前调用的方法,查找拦截器链。如果你读过之前关于基于 JDK 动态代理的 AOP 代理的原理,就会发现这个用来查找拦截器链的方法很熟悉。其实,这个方法跟 JdkDynamicAopProxy 的invoke方法中调用的getInterceptorsAndDynamicInterceptionAdvice方法是同一个方法。

关于这个方法的原理,我之前写过 4 篇文章来详细介绍,可以阅读之前的文章来了解其中的原理。

传送门:如何获取拦截器链:1234

拦截器的执行

// Check whether we only have one InvokerInterceptor: that is,// no real advice, but just reflective invocation of the target.if (chain.isEmpty() &&Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.// Note that the final invoker must be an InvokerInterceptor, so we know// it does nothing but a reflective operation on the target, and no hot// swapping or fancy proxying.Object[] argsToUse=AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal=methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...retVal=newCglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}

接下来就是对获取到的拦截器链进行判断,如果拦截器链是空的,且方法是public修饰的,则不需要执行拦截器的逻辑。在if语句块中,首先通过 AopProxyUtils 类的adaptArgumentsIfNecessary方法,对调用方法的参数进行处理,这里主要是在有必要的情况下,对方法参数列表中的可变参数进行类型适配。然后,通过methodProxyinvoke方法直接调用目标方法。

如果拦截器链不为空,那么则会通过构造方法创建一个 CglibMethodInvocation 对象,然后调用它的proceed方法,执行拦截器链的增强逻辑。

我们先看一下 CglibMethodInvocation 类。

可以看到,它是 ReflectiveMethodInvocation 的子类,而 ReflectiveMethodInvocation 是基于 JDK 动态代理的 AOP 代理回调方法中用来执行拦截器链逻辑的类型,因此可以推测,这两种代理方式的拦截器链执行逻辑应该也大同小异。

接下来看一下 CglibMethodInvocation 的类定义和构造方法。

privatestaticclassCglibMethodInvocationextendsReflectiveMethodInvocation {
@NullableprivatefinalMethodProxymethodProxy;
publicCglibMethodInvocation(Objectproxy, @NullableObjecttarget, Methodmethod,
Object[] arguments, @NullableClass<?>targetClass,
List<Object>interceptorsAndDynamicMethodMatchers, MethodProxymethodProxy) {
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
// Only use method proxy for public methods not derived from java.lang.Objectthis.methodProxy= (Modifier.isPublic(method.getModifiers()) &&method.getDeclaringClass() !=Object.class&&!AopUtils.isEqualsMethod(method) &&!AopUtils.isHashCodeMethod(method) &&!AopUtils.isToStringMethod(method) ?methodProxy : null);
   }
// 省略其他代码}

它是 CglibAopProxy 的一个静态内部类,在构造方法中,调用了父类的构造方法,也就是 ReflectiveMethodInvocation 的构造方法,此外,还初始化了methodProxy变量。methodProxy初始化的逻辑也比较简单,主要是确保被代理的方法是public修饰的不是声明在 Object 中的方法,且不是equalshashCodetoString这三个方法。

对父类构造方法的调用主要是一些属性的初始化,之前介绍 ReflectiveMethodInvocation 的时候,已经介绍过,这里不再赘述。

了解完构造方法之后,再看其执行拦截器链逻辑的proceed方法。

// org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#proceed@Override@NullablepublicObjectproceed() throwsThrowable {
try {
returnsuper.proceed();
   }
catch (RuntimeExceptionex) {
throwex;
   }
catch (Exceptionex) {
if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) {
throwex;
      }
else {
thrownewUndeclaredThrowableException(ex);
      }
   }
}

其核心逻辑只有一行,就是调用父类的proceed方法,也就是 ReflectiveMethodInvocation 的proceed方法,到这里,接下来的逻辑就跟基于 JDK 动态代理的 AOP 代理回调执行拦截器链的逻辑相同了,在之前的文章中,也详细分析过这个方法的执行逻辑,你可以通过之前的文章来了解其中的细节。

传送门:ReflectiveMethodInvocation 分析MethodInterceptor 分析

总结

本文分析了基于 CGLIB 的 AOP 代理如何查找和执行拦截器链,其主要的逻辑在 DynamicAdvisedInterceptor 的intercept方法执行。对于拦截器链的查找和执行逻辑,与基于 JDK 动态代理的 AOP 代理的执行逻辑共用了大部分的代码。

目录
相关文章
|
2月前
|
Java 应用服务中间件 Spring
Spring5源码(50)-SpringMVC源码阅读环境搭建
Spring5源码(50)-SpringMVC源码阅读环境搭建
42 0
|
2月前
|
XML Java 数据格式
5个点轻松搞定Spring AOP底层实现原理
AOP 也是 Spring 中一个较为重要的内容,相对于传统的 OOP 模式,AOP 有很多让人难以理解的地方,本篇文章将向大家介绍 AOP 的实现方法及其底层实现,内容包括:
47 1
|
3天前
|
前端开发 Java Spring
[AIGC] Spring Interceptor 拦截器详解
[AIGC] Spring Interceptor 拦截器详解
|
1月前
|
缓存 前端开发 Java
【Spring底层原理高级进阶】轻松掌握 Spring MVC 的拦截器机制:深入理解 HandlerInterceptor 接口和其实现类的用法
【Spring底层原理高级进阶】轻松掌握 Spring MVC 的拦截器机制:深入理解 HandlerInterceptor 接口和其实现类的用法
|
2月前
|
XML Java 数据格式
浅谈基于动态代理的Spring AOP原理
浅谈基于动态代理的Spring AOP原理
26 0
|
2月前
|
设计模式 安全 Java
深入理解Spring Boot AOP:CGLIB代理与JDK动态代理的完全指南
深入理解Spring Boot AOP:CGLIB代理与JDK动态代理的完全指南
322 1
|
2月前
spring-state-machine拦截器
spring-state-machine拦截器
24 0
|
2月前
|
缓存 Java uml
SpringBoot2 | Spring AOP 原理深度源码分析(八)
SpringBoot2 | Spring AOP 原理深度源码分析(八)
48 0
|
2月前
Spring5源码(27续)-cglib原理解析
Spring5源码(27续)-cglib原理解析
15 0
|
3月前
|
Java Spring
Spring AOP之MethodInterceptor原理
Spring AOP之MethodInterceptor原理
81 0