Spring的AOP基于代理模式,并且它即使用到了JDK动态代理也使用了Cglib代理。
如下代码是springAOP中默认的代理实现类DefaultAopProxyFactory,其中创建代理的方法createAopProxy,在这个方法中Spring通过判断targetClass是否有实现接口来确定使用哪一种代理,如果实现了接口则使用JDK动态代理,如果没有实现接口则使用Cglib代理。同时JdkDynamicAopProxy为JDK动态代理的生成类,ObjenesisCglibAopProxy可以生成Cglib代理。
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
public DefaultAopProxyFactory() {
}
//创建代理
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
return new JdkDynamicAopProxy(config);//生成JDK动态代理
} else {
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.");
} else {//ObjenesisCglibAopProxy生成Cglib代理
return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
}
}
}
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return ifcs.length == 0 || ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]);
}
}
从上面代码可以发现当需要被代理的类实现了接口的时候Spring会使用动态代理,当被代理的类没有接口实现的时候使用的是Cglib,我们也可以强制使用CGlib,在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>。
性能问题:由于Cglib代理是利用ASM字节码生成框架在内存中生成一个需要被代理类的子类完成代理,而JDK动态代理是利用反射原理完成动态代理,所以Cglib创建的动态代理对象性能比JDk动态代理动态创建出来的代理对象新能要好的多,但是对象创建的速度比JDk动态代理要慢,所以,当Spring使用的是单例情况下可以选用Cglib代理,反之使用JDK动态代理更加合适。同时还有一个问题,被final修饰的类只能使用JDK动态代理,因为被final修饰的类不能被继承,而Cglib则是利用的继承原理实现代理的。
关于动态代理请参考:https://my.oschina.net/zicheng/blog/1920396。