持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第28天,点击查看活动详情
基于 Spring Framework v5.2.6.RELEASE
概述
前几篇文章分析了创建 AOP 代理对象的方法createProxy中创建和配置 ProxyFactory 工厂对象的过程,在完成 ProxyFactory 初始化的所有流程之后,本文分析 ProxyFactory 是如何创建 AOP 对立对象的。
getProxy 方法
先回到createProxy方法中。
整个方法提都在配置 ProxyFactory,在最后一行,调用了proxyFactory的getProxy方法,创建了代理对象并返回。我们进入getProxy方法,看它是如何创建代理对象的。
// org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
在这个方法中,通过createAopProxy方法获取了一个 AopProxy,然后通过 AopProxy 的getProxy方法来完成了代理对象的创建。我们看一下createAopProxy方法。
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
可以看到,AopProxy 是通过getAopProxyFactory方法获取到的 AopProxyFactory 调用createAopProxy方法创建的。我们再进入getAopProxyFactory方法查看。
public AopProxyFactory getAopProxyFactory() {
return this.aopProxyFactory;
}
这里的 AopProxyFactory 其实就是成员变量aopProxyFactory,在之前的分析中,我们知道了,这里的aopProxyFactory是在 ProxyCreatorSupport 的构造方法中初始化的,它的类型是 DefaultAopProxyFactory。回到上面的createAopProxy方法中,我们再看 ProxyCreatorSupport 的createAopProxy方法。
代理创建方式的选择
// org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
这个方法中,会通过一些条件的判断,返回一个 JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy,它们分别是 JDK 动态代理和 CGLIB 代理的方式,最后调用它的getProxy方法来获得最终的代理对象。
我们来看这里是如何选择 JDK 动态代理还是 CGLIB 代理的。先看第一个if语句中的三个判断条件。
第一个判断条件是config.isOptimize(),这里的config是方法参数传入的,其实就是之前创建的 ProxyFactory 工厂对象,它的optimize属性是 ProxyFactory 创建后,通过copyFrom方法从后处理器中复制的属性值,它的默认值是false。
第二个判断条件是config.isProxyTargetClass(),proxyTargetClass可以在开启 AOP 特性时进行配置,在 ProxyFactory 初始化的过程中,也根据目标 Bean 得情况进行了配置,这里不再赘述。
第三个判断条件hasNoUserSuppliedProxyInterfaces方法的执行结果,我们进入这个方法查看判断逻辑。
// org.springframework.aop.framework.DefaultAopProxyFactory#hasNoUserSuppliedProxyInterfaces
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
这里的config中的proxiedInterfaces属性的值,其实就是目标 Bean 的类型实现的接口,因此,这里的逻辑就是,如果当前 Bean 的类型没有实现接口,或者只实现了一个 SpringProxy 接口,那么返回true。
以上三个判断条件,只要满足其一,就进入if语句块进行进一步判断,否则返回 JdkDynamicAopProxy 采用 JDK 动态代理的方式。
我们再看if语句块看进一步判断的逻辑,如果目标 Bean 得类型是接口或者代理类,那么返回 JdkDynamicAopProxy,否则返回 ObjenesisCglibAopProxy。
至此,最终的代理对象是通过 JDK 动态代理的方式创建,还是通过 CGLIB 的方式创建,就有结果了。最后一步代理对象的创建,就是通过调用 JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy 的getProxy方法来创建。这两个类型,都实现了 AopProxy 接口,getProxy方法也是 AopProxy 接口中定义的方法。
这个方法的代码分析,包含了以上两个类型中该方法的原理,我会放到下一篇文章中分析。
总结
本文进入createProxy方法,分析了 Spring 创建代理对象的大致过程,以及如何选择 JDK 动态代理或者 CGLIB 方式来创建代理对象。下一篇讲分析这两种方式创建代理的过程。