Spring的动态代理支持cglib和jdk两种代理模式。对于两种动态代理的选择我们通常会说,当一个类实现了接口,Spring会使用jdk代理模式,否则使用cglib的代理模式。因为jdk代理要求一个类必须实现接口,而cglib代理可以将目标类当做父类来实现代理逻辑。但Spring具体在代码层级上是如何实现选择逻辑的呢?我们来看一下,先看一个类
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@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);
}
}
/**
* Determine whether the supplied {@link AdvisedSupport} has only the
* {@link org.springframework.aop.SpringProxy} interface specified
* (or no proxy interfaces specified at all).
*/
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}
这个类就是用来创建代理的,在它的createAopProxy方法中实现了对cglib代理(ObjenesisCglibAopProxy)和jdk代理(JdkDynamicAopProxy)的选择。代码逻辑比较简单,对我们分析问题有用的是两个if判断,即
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
第一个if是基于传入参数AdvisedSupport的配置信息来判断是创建cglib代理还是jdk代理。我们看下AdvisedSupport类的类图
AdvisedSupport继承自ProxyConfig。类如其名,ProxyConfig是用来管理代理的一些配置属性,包括下面的五种
private boolean proxyTargetClass = false; private boolean optimize = false; boolean opaque = false; boolean exposeProxy = false; private boolean frozen = false;
结合if条件和配置属性,我们来看具体的选择逻辑
1、满足配置optimize为false,proxyTargetClass为false,并且目标类没有实现接口或者目标类实现了一个接口,但该接口为SpringProxy的子接口,则创建jdk代理
2、不满足条件1,但目标类为接口或者目标类为代理类(Proxy类的子类),则创建jdk代理
3、不满足条件1、2,则创建cglib代理