基于 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)publicObjectgetProxy(ClassLoaderclassLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating JDK dynamic proxy: "+this.advised.getTargetSource()); } Class<?>[] proxiedInterfaces=AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); returnProxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
首先,会通过 AopProxyUtils 的completeProxiedInterfaces
方法,获取要代理的接口数组。调用方法时,传入的参数this.advised
成员变量,是在 JdkDynamicAopProxy 的构造方法中初始化的。
// org.springframework.aop.framework.JdkDynamicAopProxy#JdkDynamicAopProxypublicJdkDynamicAopProxy(AdvisedSupportconfig) throwsAopConfigException { Assert.notNull(config, "AdvisedSupport must not be null"); if (config.getAdvisors().length==0&&config.getTargetSource() ==AdvisedSupport.EMPTY_TARGET_SOURCE) { thrownewAopConfigException("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#findDefinedEqualsAndHashCodeMethodsprivatevoidfindDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) { for (Class<?>proxiedInterface : proxiedInterfaces) { Method[] methods=proxiedInterface.getDeclaredMethods(); for (Methodmethod : 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 框架的范畴,就不深入分析了,我们找到这个方法的定义,大概了解一下这几个参数。
publicstaticObjectnewProxyInstance(ClassLoaderloader, Class<?>[] interfaces, InvocationHandlerh) { // 省略方法体中的代码}
第一个参数loader
是创建代理的类加载器,第二个参数interfaces
是代理对象要实现的所有接口,也就是上一步我们得到的代理接口列表。这两个参数比较好理解。
第三个参数的类型是 InvocationHandler,这个参数方法调用的处理器,也就是对代理对象的方法调用回分派到这个 InvocationHandler 对象中,在上一步中通过newProxyInstance
创建代理对象的时候,这个参数传入的是this
,也就是在 DefaultAopProxyFactory 中创建的 JdkDynamicAopProxy 对象,也就是说,对代理对象的方法调用,都是由它来完成的。
从上面的接口中,可以看到 JdkDynamicAopProxy 是实现了 InvocationHandler 接口的,主要的处理逻辑在 InvocationHandler 接口定义的invoke
方法中。
通过 CGLIB 创建代理对象
下面接着分析 CGLIB 代理对象的创建,也就是 ObjenesisCglibAopProxy 的getProxy
方法,在此之前,我们先看一下它的构造方法,看看代理对象被创建之前,创建 ObjenesisCglibAopProxy 的时候执行了哪些工作。
// org.springframework.aop.framework.ObjenesisCglibAopProxy#ObjenesisCglibAopProxypublicObjenesisCglibAopProxy(AdvisedSupportconfig) { super(config); }
只是调用了父类的构造方法,我们再跟着找到父类的构造方法。
// org.springframework.aop.framework.CglibAopProxy#CglibAopProxypublicCglibAopProxy(AdvisedSupportconfig) throwsAopConfigException { Assert.notNull(config, "AdvisedSupport must not be null"); if (config.getAdvisors().length==0&&config.getTargetSource() ==AdvisedSupport.EMPTY_TARGET_SOURCE) { thrownewAopConfigException("No advisors and no TargetSource specified"); } this.advised=config; this.advisedDispatcher=newAdvisedDispatcher(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...Enhancerenhancer=createEnhancer(); if (classLoader!=null) { enhancer.setClassLoader(classLoader); if (classLoaderinstanceofSmartClassLoader&& ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { enhancer.setUseCache(false); } } enhancer.setSuperclass(proxySuperClass); enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setStrategy(newClassLoaderAwareGeneratorStrategy(classLoader)); Callback[] callbacks=getCallbacks(rootClass); Class<?>[] types=newClass<?>[callbacks.length]; for (intx=0; x<types.length; x++) { types[x] =callbacks[x].getClass(); } // fixedInterceptorMap only populated at this point, after getCallbacks call aboveenhancer.setCallbackFilter(newProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); enhancer.setCallbackTypes(types);
接下来就是创建 Enhancer,并设置它的一些属性。Enhancer 字节码增强器是 CGLIB 创建代理对象的一个重要的类。这里设置了类加载器、父类(也就是代理的目标类型)、回调过滤器、回调类型数组等。
returncreateProxyClassAndInstance(enhancer, callbacks);
最后,通过createProxyClassAndInstance
方法创建了代理对象,我们再进入createProxyClassAndInstance
方法看一下。
这里需要注意,因为之前创建的 AopProxy 对象是 ObjenesisCglibAopProxy 类型,因此,ObjenesisCglibAopProxy 类型中实现了这个方法,我们应该看 ObjenesisCglibAopProxy 中的实现逻辑。
其中比较关键的逻辑,是通过enhancer.createClass()
来创建代理类型,以及通过objenesis
.newInstance
来创建代理对象实例,不过,这些都属于 CGLIB 的内容,不在 Spring 框架的范畴之内,这里不做介绍了。
总结
本文分别分析了 Spring 通过 JDK 动态代理和 CGLIB 两种方式创建 AOP 代理对象的过程。至此,Spring AOP 特性中,代理对象创建的全部过程就分析完了。