Spring深度学习:动态代理源码解析


Spring深度学习:动态代理源码解析

一、序言

大家经常戏称Java工程师为Spring工程师,毫无疑问,这句话体现出Spring框架在Java开发中的重要性和普及度。

本文小豪将带大家深度学习Spring动态代理相关知识,包括JDK和Cglib两种动态代理的底层实现原理,以及代理对象回调时拦截链执行过程的源码分析,深入研究动态代理的内部机制,进一步理解面向切面编程的思想,提升我们的架构能力。

文章最后附有思维导图,串联动态代理相关的知识体系,加深记忆

二、前置知识

在学习本文之前,大家可先自行阅读上一篇【Spring深度学习:AOP创建过程源码解析】,本文将延续上一篇思路,解读两种动态代理的创建过程以及方法调用后的执行处理逻辑。

在上一篇中,遗留了两个问题:

  1. 为什么需要在Advisors增强器列表头部添加一个Spring内置的ExposeInvocationInterceptor类型的Advisor,它有什么作用?
  2. 为什么Advisors增强器列表经过排序后After后置通知却排在Before前置通知之前,不会影响后续执行顺序吗?

相信大家经过本文,会彻底搞清楚这两个疑问。

在进行动态代理解读之前,小豪先大致讲一下JDK和Cglib两种动态代理的实现逻辑,让大家先有初步概念。

  • JDK动态代理:JDK动态代理是基于接口实现的,本质上是通过实现与目标类相同的接口,通过反射机制获取到接口里面的方法,生成的代理对象与目标类属于同层级
  • Cglib动态代理:JDK动态代理是基于目标类本身实现的,本质上是通过继承机制,生成目标类的虚拟子类,重写目标类的方法,代理对象与目标类属于父子级

其中Cglib依赖于ASM字节码技术来操作字节码,实现在运行时动态生成代理,而JDK由Java自身的反射机制来实现

三、动态代理

在上一篇我们了解到ProxyFactory代理工厂创建代理对象关键的两步:

  1. createAopProxy():选择并创建AopProxy接口的实现类
  2. 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动态代理是基于接口的,因此肯定需要获取目标类的接口,同时修正了一下接口中的equalshashCode方法,最后调用**Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)**方法创建代理实例,方法传入三个参数:

  1. 参数一classLoader类加载器
  2. 参数二proxiedInterfaces目标类的代理接口
  3. 参数三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"));
	}
}

看到这里,想必大家也能初步串联起来整体流程了,总结一下:

  1. JDK动态代理生成的代理类对象$Proxy1实现了目标类UserServiceImpl的接口IUserService,通过构造方法注入LogInvocationHandler方法调用拦截器,重写了IUserService接口的login()方法,同时利用反射机制拿到实际的login()方法
  2. 当调用代理类对象$Proxy1login()方法时,实际上会调用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代理类对象的创建执行流程:

  1. Cglib动态代理生成的$$Enhancer代理类对象继承了目标类UserService,重新了目标类UserServicelogin()方法,通过set方法注入了LogMethodInterceptor方法调用拦截器

  2. 当调用代理类对象$$Enhancerlogin()方法时,首先会进行判断

    • 拦截器不为空:调用LogMethodInterceptor方法调用拦截器的intercept()方法,方法调用拦截器会执行实际目标类UserService对象的login()方法,同时在执行过程中触发相应的增强逻辑
    • 拦截器为空:直接调用目标类UserServicelogin()方法

在这里我们也可以得出一个结论:由于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动态代理模拟实现中了解到,调用代理类方法,实际上最后将会执行方法调用拦截器MethodInterceptorintercept()方法实现增强。

而在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);

不出所料,这里将会正常拿到之前获得到的三个拦截器:

  1. ExposeInvocationInterceptor
  2. AspectJAfterAdvice
  3. 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();
	}

发现MethodBeforeAdviceInterceptorinvoke()方法,会首先触发前置通知完成增强,然后继续执行下一个拦截器。

(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底层源码其它系列文章哦~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值