Spring深度学习:动态代理源码解析
一、序言
大家经常戏称Java工程师为Spring工程师,毫无疑问,这句话体现出Spring框架在Java开发中的重要性和普及度。
本文小豪将带大家深度学习Spring动态代理相关知识,包括JDK和Cglib两种动态代理的底层实现原理,以及代理对象回调时拦截链执行过程的源码分析,深入研究动态代理的内部机制,进一步理解面向切面编程的思想,提升我们的架构能力。
文章最后附有思维导图,串联动态代理相关的知识体系,加深记忆
二、前置知识
在学习本文之前,大家可先自行阅读上一篇【Spring深度学习:AOP创建过程源码解析】,本文将延续上一篇思路,解读两种动态代理的创建过程以及方法调用后的执行处理逻辑。
在上一篇中,遗留了两个问题:
- 为什么需要在
Advisors
增强器列表头部添加一个Spring内置的ExposeInvocationInterceptor
类型的Advisor
,它有什么作用? - 为什么
Advisors
增强器列表经过排序后After
后置通知却排在Before
前置通知之前,不会影响后续执行顺序吗?
相信大家经过本文,会彻底搞清楚这两个疑问。
在进行动态代理解读之前,小豪先大致讲一下JDK和Cglib两种动态代理的实现逻辑,让大家先有初步概念。
- JDK动态代理:JDK动态代理是基于接口实现的,本质上是通过实现与目标类相同的接口,通过反射机制获取到接口里面的方法,生成的代理对象与目标类属于同层级
- Cglib动态代理:JDK动态代理是基于目标类本身实现的,本质上是通过继承机制,生成目标类的虚拟子类,重写目标类的方法,代理对象与目标类属于父子级
其中Cglib依赖于ASM字节码技术来操作字节码,实现在运行时动态生成代理,而JDK由Java自身的反射机制来实现
三、动态代理
在上一篇我们了解到ProxyFactory
代理工厂创建代理对象关键的两步:
- createAopProxy():选择并创建
AopProxy
接口的实现类 - getProxy(classLoader):调用
AopProxy
接口的实现类的getProxy()
拿到具体的代理类
上一篇已经介绍过createAopProxy()
方法会经过条件判断选择生成不同类型的动态代理,不再赘述,本节小豪会先带大家解读两种动态代理实现类getProxy()
方法的源码,然后模拟动态代理创建执行过程,深入动态代理的底层实现原理
1、JDK动态代理
(1)Jdk动态代理getProxy源码
我们首先进入JdkDynamicAopProxy
类的getProxy()
方法,具体源码如下:
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
// JDK动态代理是基于接口的,这里需要获取目标类的接口列表
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
// 判断并修改接口中的equals和hashCode方法
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 创建JDK代理实例
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
源码也比较简单,由于JDK动态代理是基于接口的,因此肯定需要获取目标类的接口,同时修正了一下接口中的equals
和hashCode
方法,最后调用**Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)**方法创建代理实例,方法传入三个参数:
- 参数一:
classLoader
类加载器 - 参数二:
proxiedInterfaces
目标类的代理接口 - 参数三:
this
指代当前类JdkDynamicAopProxy
,当前类实现自InvocationHandler
接口
JDK动态代理中Proxy和InvocationHandler是比较关键的点
Proxy为生成代理类的父类
InvocationHandler为方法调用拦截器,后续调用目标类的方法都是通过该接口的invoke()方法来完成的
(2)JDK动态代理模拟实现
接下来我们手动实现JDK动态代理
2.1 环境模拟
User实体类:
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
IUserService接口:
JDK动态代理基于接口,此处需创建Service
接口
public interface IUserService {
/**
* 用户登录
*/
boolean login(String name);
}
UserServiceImpl实现类:
public class UserServiceImpl implements IUserService {
public boolean login(String name) {
System.out.println("欢迎登录:" + name);
return true;
}
}
LogUtils增强类:
public class LogUtils {
// 前置通知
public void before(){
System.out.println("start execute log before..");
}
// 后置通知
public void after(){
System.out.println("start execute log after..");
}
}
LogInvocationHandler实现类:
LogInvocationHandler
用于实现InvocationHandler
接口,实现其invoke()
方法,作为方法调用拦截器
public class LogInvocationHandler implements InvocationHandler {
// 增强类对象
private LogUtils logAdvisor;
// 目标类对象
private Object targetUserObj;
// 通过构造方法注入LogUtils增强类和UserServiceImpl目标类
public LogInvocationHandler(LogUtils logUtils, Object targetUserObj) {
this.logAdvisor = logUtils;
this.targetUserObj = targetUserObj;
}
/*
proxy 代理对象
method 目标类方法
args 目标类方法入参
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object returnObj = null;
// 执行前置通知
logAdvisor.before();
// 执行实际目标类对象方法
returnObj = method.invoke(targetUserObj, args);
// 执行后置通知
logAdvisor.after();
return returnObj;
}
}
JdkProxyCreateTest测试类:
调用Proxy.newProxyInstance()
方法创建JDK代理类对象
public class JdkProxyCreateTest {
public static void main(String[] args) {
// 创建目标类对象
IUserService targetUser = new UserServiceImpl();
// 创建增强类对象
LogUtils logAdvisor = new LogUtils();
// 创建方法调用拦截器
LogInvocationHandler logInvocationHandler = new LogInvocationHandler(logAdvisor, targetUser);
// 获取JDK动态代理实例对象
IUserService userProxy = (IUserService)
Proxy.newProxyInstance(
// 类加载器
UserServiceImpl.class.getClassLoader(),
// 目标类实现的所有接口
UserServiceImpl.class.getInterfaces(),
// 方法调用拦截器
logInvocationHandler);
// 调用代理方法
userProxy.login("小豪");
}
}
控制台测试结果:
start execute log before..
欢迎登录:小豪
start execute log after..
2.2 代理对象源码
这里我们可以通过Java自带的命令行工具jps或者借助一些外部性能分析工具,反编译代理类对象拿到源码,生成的具体代理类对象源码如下:
import com.jdkproxy.IUserService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy1 extends Proxy implements IUserService {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy1(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final boolean login(String var1) throws {
try {
return (Boolean)super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.jdkproxy.IUserService").getMethod("login", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
生成的代理类对象源码有点长,部分内容先不用关注,我们进一步将它精简一下:
public final class $Proxy1 extends Proxy implements IUserService {
// m3代表login()方法
private static Method m3;
// 通过构造方法注入InvocationHandler方法调用拦截器,赋值给super.h属性
public $Proxy1(InvocationHandler var1) throws {
super(var1);
}
public final boolean login(String var1) throws {
// 实际上调用LogInvocationHandler对象的invoke()方法
// 【m3】 = login()方法
// 【var1】 = login()的入参
return (Boolean)super.h.invoke(this, m3, new Object[]{var1});
}
static {
// 通过反射获取IUserService接口的login()方法
m3 = Class.forName("com.jdkproxy.IUserService").getMethod("login", Class.forName("java.lang.String"));
}
}
看到这里,想必大家也能初步串联起来整体流程了,总结一下:
- JDK动态代理生成的代理类对象
$Proxy1
实现了目标类UserServiceImpl
的接口IUserService
,通过构造方法注入LogInvocationHandler
方法调用拦截器,重写了IUserService
接口的login()
方法,同时利用反射机制拿到实际的login()
方法 - 当调用代理类对象
$Proxy1
的login()
方法时,实际上会调用LogInvocationHandler
方法调用拦截器的invoke()
方法,方法调用拦截器会执行实际目标类UserServiceImpl
对象的login()
方法,同时在执行过程中触发相应的增强逻辑。
2.3 底层执行流程
2、Cglib动态代理
(1)Cglib动态代理getProxy源码
介绍完JDK动态代理,开始分析Cglib动态代理,同样,我们先查看CglibAopProxy
类的getProxy()
方法源码:
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
}
try {
// this.advised就是先前创建的ProxyFactory代理工厂
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class<?> proxySuperClass = rootClass;
// 判断目标类是否已经是Cglib代理对象,如果是则使用目标类的父类作为目标类
if (ClassUtils.isCglibProxyClass(rootClass)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// 检验合法性
validateClassIfNecessary(proxySuperClass, classLoader);
// 创建Enhancer
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
// Enhancer的一系列配置工作
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
// 获取回调方法集合callbacks
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// 设置Callback过滤器
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// 创建代理对象并设置回调
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
Cglib创建动态代理的代码有点长,简单概括下:首先进行了一些列检验工作,然后创建Enhancer
,为其设置相关的属性,包括目标类以及回调方法集合callbacks
。
其中getCallbacks()
会生成代理类的回调方法集合,具体看一下它的源码:
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// 获取ProxyFactory代理工厂的部分属性
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
// 创建AOP拦截器,DynamicAdvisedInterceptor为具体的实现类
// this.advised其实就是上一篇getAdvicesAndAdvisorsForBean()方法获取的符合要求的Advisor增强器
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
// 根据是否暴露代理类以及是否静态,生成不同的拦截器
Callback targetInterceptor;
if (exposeProxy) {
targetInterceptor = (isStatic ?
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
}
else {
targetInterceptor = (isStatic ?
new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
}
Callback targetDispatcher = (isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());
// 创建回调集合,包括核心的拦截器aopInterceptor
Callback[] mainCallbacks = new Callback[] {
aopInterceptor, // for normal advice
targetInterceptor, // invoke target without considering advice, if optimized
new SerializableNoOp(), // no override for methods mapped to this
targetDispatcher, this.advisedDispatcher,
new EqualsInterceptor(this.advised),
new HashCodeInterceptor(this.advised)
};
Callback[] callbacks;
// 如果目标类是静态并且配置冻结
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap<>(methods.length);
for (int x = 0; x < methods.length; x++) {
Method method = methods[x];
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
this.fixedInterceptorMap.put(methods.toString(), x);
}
callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
this.fixedInterceptorOffset = mainCallbacks.length;
}
else {
callbacks = mainCallbacks;
}
return callbacks;
}
我们看到内部主要是将Advisor
增强器封装为DynamicAdvisedInterceptor
,然后放入Callback[]
回调集合的首位。这里的DynamicAdvisedInterceptor
类实现自MethodInterceptor
接口
Cglib动态代理中Enhancer和MethodInterceptor是核心
Enhancer为Cglib包装的代理对象
MethodInterceptor方法调用拦截器,后续调用目标类的方法都会通过该接口的intercept()方法拦截,作用类似于JDK动态代理中的InvocationHandler
(2)Cglib动态代理模拟实现
接下来,我们继续模拟一下Cglib动态代理的实现
2.1 环境模拟
User实体类、LogUtils增强类不进行变动
UserService实现类:
由于Cglib动态代理的实现可以不需要目标类存在接口,因此我们删掉IUserService
接口,同时修改一下UserService
实现类
public class UserService {
public boolean login(String name) {
System.out.println("欢迎登录:" + name);
return true;
}
}
LogMethodInterceptor实现类:
LogMethodInterceptor
用于实现MethodInterceptor
接口,实现其intercept()
方法,作为方法调用拦截器
public class LogMethodInterceptor implements MethodInterceptor {
//增强类对象
private LogUtils logAdvisor;
public LogMethodInterceptor(LogUtils logUtils) {
this.logAdvisor = logUtils;
}
/*
o 代理对象
method 目标类方法
objects 目标类方法入参
methodProxy 代理类对象的方法代理
*/
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
// 执行前置通知
logAdvisor.before();
// 执行实际目标类对象方法
Object ret = methodProxy.invokeSuper(o, objects);
// 执行后置通知
logAdvisor.after();
return ret;
}
}
CgLibProxyCreateTest测试类:
创建Enhancer
对象,设置目标类及方法回调,生成Cglib代理类对象
public class CgLibProxyCreateTest {
public static void main(String[] args) {
// 创建增强类对象
LogUtils logAdvisor = new LogUtils();
// 创建方法调用拦截器
LogMethodInterceptor logMethodInterceptor = new LogMethodInterceptor(logAdvisor);
// 创建Enhancer,生成目标类的代理类
Enhancer enhancer = new Enhancer();
// 设置父类Class(目标类)
enhancer.setSuperclass(UserService.class);
// 设置方法调用拦截器
enhancer.setCallback(logMethodInterceptor);
// 获取CgLib动态代理实例对象
UserService userProxy = (UserService) enhancer.create();
// 调用代理方法
userProxy.login("小豪");
}
}
控制台测试结果:
start execute log before..
欢迎登录:小豪
start execute log after..
2.2 代理对象源码
这里我们同样借助外部工具生成Cglib的代理类对象,精简后的源码如下:
public class UserService$$EnhancerByCGLIB$$332a5dd5 extends UserService implements Factory {
// LogMethodInterceptor方法调用拦截器
private MethodInterceptor CGLIB$CALLBACK_0;
public final boolean login(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
// 方法调用拦截器不为空则执行增强,否则直接执行原目标类方法
if (var10000 != null) {
// 实际上调用LogMethodInterceptor对象的intercept()方法
// 【CGLIB$login$0$Method】 = login()方法
// 【var1】= login()的入参
// 【CGLIB$login$0$Proxy】 = login()方法的代理
Object var2 = var10000.intercept(this, CGLIB$login$0$Method, new Object[]{var1}, CGLIB$login$0$Proxy);
return var2 == null ? false : (Boolean)var2;
} else {
return super.login(var1);
}
}
// 通过set方法注入MethodInterceptor方法调用拦截器,赋值给CGLIB$CALLBACK_0
public void setCallbacks(Callback[] var1) {
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
}
}
再次总结一下Cglib代理类对象的创建执行流程:
-
Cglib动态代理生成的
$$Enhancer
代理类对象继承了目标类UserService
,重新了目标类UserService
的login()
方法,通过set方法注入了LogMethodInterceptor
方法调用拦截器 -
当调用代理类对象
$$Enhancer
的login()
方法时,首先会进行判断- 拦截器不为空:调用
LogMethodInterceptor
方法调用拦截器的intercept()
方法,方法调用拦截器会执行实际目标类UserService
对象的login()
方法,同时在执行过程中触发相应的增强逻辑 - 拦截器为空:直接调用目标类
UserService
的login()
方法
- 拦截器不为空:调用
在这里我们也可以得出一个结论:由于Cglib生成的代理类对象继承自目标类,重写目标方法,因此,Cglib动态代理不能实现对final
修饰的方法或类进行代理
两种动态代理基本介绍结束了,这里小豪给大家抛个疑问,哪一种动态代理的效率更好呢?
2.3 底层执行流程
四、方法调用
接着我们来解读代理类对象方法调用后的执行处理逻辑,回到上一篇【Spring深度学习:AOP创建过程源码解析】的测试类:SpringDemo
public class SpringDemo {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-config.xml");
// 此处的user已经是Cglib动态代理类对象,User$$Enhancer
User user = (User) applicationContext.getBean("user");
// 调用代理类方法
user.hello();
}
}
此时我们的user
对象其实已经是经过Cglib动态代理后的代理类对象,在我们上面Cglib动态代理模拟实现中了解到,调用代理类方法,实际上最后将会执行方法调用拦截器MethodInterceptor
的intercept()
方法实现增强。
而在Spring源码CglibAopProxy.getProxy()
创建Cglib动态代理时,会先调用getCallbacks()
方法拿到代理类的回调方法集合,而回调方法集合中会又会进一步创建DynamicAdvisedInterceptor
类,作为AOP调用拦截器,此处的DynamicAdvisedInterceptor
类实现自MethodInterceptor
接口。
因此我们直接进入DynamicAdvisedInterceptor
类的intercept()
方法:
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
// 获取目标类信息
TargetSource targetSource = this.advised.getTargetSource();
try {
// 是否需要暴露代理对象
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 获取目标类对象
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 获取所有匹配当前类的方法的AOP拦截器(拦截链)
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// 判断拦截链是否为空 && 方法修饰符为Public
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// 参数转换
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
// 调用目标类的实际目标方法
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// 创建CglibMethodInvocation方法调用类,最终调用proceed()执行拦截链
// CglibMethodInvocation继承自ReflectiveMethodInvocation父类,CglibMethodInvocation没有对proceed()方法重写,这里调用的是父类的proceed()方法
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
// 处理返回类型
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
观察源码发现,intercept()
方法大致做了如下工作:
- 获取目标类信息:首先获取目标类的相关信息,判断是否需要暴露
- 获取拦截链:根据目标类的方法,匹配符合该方法的拦截器,拿到拦截链
- 执行拦截链:创建
CglibMethodInvocation
方法调用类,调用拦截链 - 处理返回类型并返回:处理目标类方法的返回值类型并返回
我们着重关注两个很重要的步骤:
// 关键步骤一:获取拦截链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
不出所料,这里将会正常拿到之前获得到的三个拦截器:
- ExposeInvocationInterceptor
- AspectJAfterAdvice
- MethodBeforeAdviceInterceptor
// 关键步骤二:执行拦截链(递归方式)
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
1、获取拦截链
其中getInterceptorsAndDynamicInterceptionAdvice()
方法,主要是拿到匹配当前调用方法的所有拦截器,其中也涉及到一种设计模式:适配器模式
// 包装为统一的MethodInterceptor拦截器
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
这里的getInterceptors()
方法主要是将所有的advisor
增强器统一适配为xxxInterceptor
拦截器,getInterceptors()
方法具体的实现类为DefaultAdvisorAdapterRegistry
,在DefaultAdvisorAdapterRegistry
类中,通过其构造方法分别注册了前置通知、返回通知和异常通知的适配器:
public DefaultAdvisorAdapterRegistry() {
//MethodBeforeAdvice -> MethodBeforeAdviceInterceptor
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
DefaultAdvisorAdapterRegistry
类的getInterceptors()
方法,则会根据传入的advisor
,最终适配为各自对应的拦截器对象:
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
// 统一转换为MethodInterceptor拦截器,采用适配器模式(构造方法中注册了三个适配器)
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[0]);
}
2、递归执行拦截链
获取到拦截链之后,最终将会通过ReflectiveMethodInvocation
类的proceed()
方法递归执行链式调用,同时这里也涉及到另一种设计模式:责任链模式
public Object proceed() throws Throwable {
// 如果拦截链中的所有拦截器调用结束,则执行真正的目标方法(递归终止条件)
// currentInterceptorIndex默认值为-1,即从索引为-1的拦截器开始调用
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 获取下一个拦截器 ++index
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 判断下个拦截器是否为动态拦截器
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
// 判断是否匹配
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// 递归调用下一个拦截器
return proceed();
}
}
else {
// 下个拦截器是普通拦截器,直接调用,传入this
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
查看源码发现,首先proceed()
方法定义了一个currentInterceptorIndex索引,默认指向-1,每次都会通过++index
获取下一个将要被执行的拦截器,然后递归调用下个拦截器的invoke()
方法,当index
索引等于拦截链的长度-1时(即递归终止条件),则执行目标类的方法,从而结束递归。
接下来我们跟着调用流程走一遍:
首次proceed()
方法进来,index
默认值为-1,++index
获取到索引为0的拦截器ExposeInvocationInterceptor
,调用其invoke()
方法:
(1)调用ExposeInvocationInterceptor
ExposeInvocationInterceptor
类源码如下:
private static final ThreadLocal<MethodInvocation> invocation =
new NamedThreadLocal<>("Current AOP method invocation");
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
// 将当前MethodInvocation拦截链调用对象存入ThreadLocal
invocation.set(mi);
try {
// 执行下一个拦截器
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
发现其invoke()
方法,主要是将我们的MethodInvocation
拦截链调用对象存入ThreadLocal
变量中,看到ThreadLocal
想必大家已经能猜到ExposeInvocationInterceptor
拦截器的作用了,没错,正是用来保存MethodInvocation
对象的,便于传递给后续的拦截器。具体作用真是这样吗,我们接着往下看。
紧接通过mi.proceed()
着我们再次回到ReflectiveMethodInvocation
类的proceed()
方法,此时index
值为0,再次++index
获取到索引为1的拦截器AspectJAfterAdvice
(2)调用AspectJAfterAdvice
AspectJAfterAdvice
类源码如下:
public Object invoke(MethodInvocation mi) throws Throwable {
try {
// 执行下一个拦截器
return mi.proceed();
}
finally {
// 执行完下一个拦截器后,回到本方法,触发后置通知
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
观察源码AspectJAfterAdvice
拦截器将会先递归调用下一个拦截器,当下一个拦截器执行结束之后,再次回到方法内部,通过finally
最终触发后置通知,完整增强。
在这里我们先暂停一下,invokeAdviceMethod()
方法的入参是通过一个getJoinPointMatch()
方法,进入getJoinPointMatch()
方法,源码如下:
protected JoinPointMatch getJoinPointMatch() {
// 获取ThreadLocal中的MethodInvocation拦截链调用对象
MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
return getJoinPointMatch((ProxyMethodInvocation) mi);
}
public static MethodInvocation currentInvocation() throws IllegalStateException {
MethodInvocation mi = invocation.get();
return mi;
}
看到这里,也就验证了本文开篇列出的第一个疑问,之前在Advisors
增强器列表头部添加的Spring内置的ExposeInvocationInterceptor
拦截器,其作用是利用ThreadLocal
线程局部变量存放MethodInvocation
对象的,用于在整个递归执行过程中传递MethodInvocation
拦截链调用对象。
返回AspectJAfterAdvice
类的invoke()
方法内部,通过执行mi.proceed()
继续执行下一个拦截器,此时++index
获取到索引为2的拦截器MethodBeforeAdviceInterceptor
,执行其invoke()
方法
(3)调用MethodBeforeAdviceInterceptor触发前置通知
MethodBeforeAdviceInterceptor
类源码如下:
public Object invoke(MethodInvocation mi) throws Throwable {
// 触发前置通知
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
// 执行下一个拦截器
return mi.proceed();
}
发现MethodBeforeAdviceInterceptor
类invoke()
方法,会首先触发前置通知完成增强,然后继续执行下一个拦截器。
(4)返回ReflectiveMethodInvocation执行目标方法
回到ReflectiveMethodInvocation
类的proceed()
方法,当前index
等于2,已经等于拦截链长度-1,会执行被代理的目标类的方法,同时结束递归
// 此时index = 拦截链-1 = 2,执行实际目标类方法,递归终止
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
(5)返回ExposeInvocationInterceptor触发后置通知
执行完目标类方法,递归会回到AspectJAfterAdvice
拦截器invoke()
方法的finally
代码块,触发后置通知增强:
finally {
// 执行完下一个拦截器后,回到本方法,触发后置通知
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
此时拦截链的流程就基本走完了,之后就会返回目标类的方法的执行结果。
最后的执行顺序为:前置通知 -> 目标方法 -> 后置通知
至此,也解释了本文开篇列出的第二个疑问,拦截链中After
后置通知排在Before
前置通知之前,并不会影响执行顺序,在递归调用过程中,当到达AspectJAfterAdvice
拦截器时,并不会直接触发后置通知,而是会先调用之后的拦截器,当之后的拦截器执行完毕后,再通过finally
完成后置通知。
五、思维导图
六、后记
本篇作为上一篇Spring AOP的延续,小豪带大家深入剖析两种动态代理的创建过程及底层原理,详解了方法回调时拦截链执行的过程源码,此外也同步解决了上一篇中遗留的问题,经过本篇文章,相信大家已经充分理解动态代理的内部机制。
在Spring框架中,采用两种动态代理方式提供了更为广泛的应用支持和灵活性,两种动态代理各有利弊,相辅相成。同时在解析源码时,其在执行拦截链过程中采用的责任链模式+递归尤为巧妙,深感Spring架构设计之强大,代码设计之优雅。
最后,如果大家觉得内容有价值,不妨考虑点点赞,关注关注小豪,后续小豪也会及时更新Spring底层源码其它系列文章哦~