持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第28天,点击查看活动详情
基于 Spring Framework v5.2.6.RELEASE
概述
上一篇分析了创建代理对象的getProxy方法,以及 Spring 如何选择使用 JDK 动态代理还是 CGLIB 来创建代理对象。本文来分析这两种方式创建代理对象的过程。
通过 JDK 动态代理创建代理对象
首先来看 Spring 通过 JDK 动态代理的方式创建 AOP 代理对象的过程,也就是 JdkDynamicAopProxy 的getProxy方法。
// org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
首先,会通过 AopProxyUtils 的completeProxiedInterfaces方法,获取要代理的接口数组。调用方法时,传入的参数this.advised成员变量,是在 JdkDynamicAopProxy 的构造方法中初始化的。
// org.springframework.aop.framework.JdkDynamicAopProxy#JdkDynamicAopProxy
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
}
这里初始化了advised成员变量的值,是参数中传入的config,而这个config就是创建 JdkDynamicAopProxy 时候的 ProxyFactory 对象。completeProxiedInterfaces方法的作用是生成完整的代理接口列表,其中包括 ProxyFactory 中配置的 Bean 类型实现的所有接口,还会增加 SpringProxy 和 Advised 接口,第二个参数传入了true,还会增加 DecoratingProxy 接口。
接下来调用了findDefinedEqualsAndHashCodeMethods方法。我们看一下这个方法的源码。
// org.springframework.aop.framework.JdkDynamicAopProxy#findDefinedEqualsAndHashCodeMethods
private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
for (Class<?> proxiedInterface : proxiedInterfaces) {
Method[] methods = proxiedInterface.getDeclaredMethods();
for (Method method : methods) {
if (AopUtils.isEqualsMethod(method)) {
this.equalsDefined = true;
}
if (AopUtils.isHashCodeMethod(method)) {
this.hashCodeDefined = true;
}
if (this.equalsDefined && this.hashCodeDefined) {
return;
}
}
}
}
从代码中可以看出,这里会遍历所有的代理接口中声明的所有方法,只要这些方法中有equals及hashCode方法,则将对应的成员变量equalsDefined或hashCodeDefined的值设置为true。这一步骤的作用尚不知道,不过既然这里这两个成员变量的值可能会在此处被修改,那么之后肯定还会遇到,到时候我们再分析它的作用。
最后一步就是代理对象的创建,调用了 JDK 动态代理的方法,创建代理对象并返回。
Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
这个方法的内容,已经不属于 Spring 框架的范畴,就不深入分析了,我们找到这个方法的定义,大概了解一下这几个参数。
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) {
// 省略方法体中的代码
}
第一个参数loader是创建代理的类加载器,第二个参数interfaces是代理对象要实现的所有接口,也就是上一步我们得到的代理接口列表。这两个参数比较好理解。
第三个参数的类型是 InvocationHandler,这个参数方法调用的处理器,也就是对代理对象的方法调用回分派到这个 InvocationHandler 对象中,在上一步中通过newProxyInstance创建代理对象的时候,这个参数传入的是this,也就是在 DefaultAopProxyFactory 中创建的 JdkDynamicAopProxy 对象,也就是说,对代理对象的方法调用,都是由它来完成的。
从上面的接口中,可以看到 JdkDynamicAopProxy 是实现了 InvocationHandler 接口的,主要的处理逻辑在 InvocationHandler 接口定义的invoke方法中。
通过 CGLIB 创建代理对象
下面接着分析 CGLIB 代理对象的创建,也就是 ObjenesisCglibAopProxy 的getProxy方法,在此之前,我们先看一下它的构造方法,看看代理对象被创建之前,创建 ObjenesisCglibAopProxy 的时候执行了哪些工作。
// org.springframework.aop.framework.ObjenesisCglibAopProxy#ObjenesisCglibAopProxy
public ObjenesisCglibAopProxy(AdvisedSupport config) {
super(config);
}
只是调用了父类的构造方法,我们再跟着找到父类的构造方法。
// org.springframework.aop.framework.CglibAopProxy#CglibAopProxy
public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
this.advisedDispatcher = new AdvisedDispatcher(this.advised);
}
这里初始化了两个成员变量,初始化advised的方式跟 JdkDynamicAopProxy 一样,而advisedDispatcher成员变量的初始化,是通过其构造方法创建了一个 AdvisedDispatcher 的对象。
接下来再分析getProxy方法,这个方法的实现也是在父类 CglibAopProxy 中,我们找到方法的代码。
方法的代码比较多,我们分步来分析,方法的逻辑都在try语句块中。
Class<?> rootClass = this.advised.getTargetClass();
首先要做的就是获取到要代理的目标类型。
Class<?> proxySuperClass = rootClass;
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
然后获取目标类型实现的接口,并将它们添加到advised成员变量配置的接口列表中。
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
接下来就是创建 Enhancer,并设置它的一些属性。Enhancer 字节码增强器是 CGLIB 创建代理对象的一个重要的类。这里设置了类加载器、父类(也就是代理的目标类型)、回调过滤器、回调类型数组等。
return createProxyClassAndInstance(enhancer, callbacks);
最后,通过createProxyClassAndInstance方法创建了代理对象,我们再进入createProxyClassAndInstance方法看一下。
这里需要注意,因为之前创建的 AopProxy 对象是 ObjenesisCglibAopProxy 类型,因此,ObjenesisCglibAopProxy 类型中实现了这个方法,我们应该看 ObjenesisCglibAopProxy 中的实现逻辑。
其中比较关键的逻辑,是通过enhancer.createClass()来创建代理类型,以及通过objenesis.newInstance来创建代理对象实例,不过,这些都属于 CGLIB 的内容,不在 Spring 框架的范畴之内,这里不做介绍了。
总结
本文分别分析了 Spring 通过 JDK 动态代理和 CGLIB 两种方式创建 AOP 代理对象的过程。至此,Spring AOP 特性中,代理对象创建的全部过程就分析完了。