Spring 源码阅读 59:确定创建 AOP 代理的方式是 JDK 动态代理还是 CGLIB

简介: 本文进入createProxy方法,分析了 Spring 创建代理对象的大致过程,以及如何选择 JDK 动态代理或者 CGLIB 方式来创建代理对象。

基于 Spring Framework v5.2.6.RELEASE

接上篇:Spring 源码阅读 58:配置 ProxyFactory 的 Advisor 列表

概述

前几篇文章分析了创建 AOP 代理对象的方法createProxy中创建和配置 ProxyFactory 工厂对象的过程,在完成 ProxyFactory 初始化的所有流程之后,本文分析 ProxyFactory 是如何创建 AOP 对立对象的。

getProxy 方法

先回到createProxy方法中。

image.png

整个方法提都在配置 ProxyFactory,在最后一行,调用了proxyFactorygetProxy方法,创建了代理对象并返回。我们进入getProxy方法,看它是如何创建代理对象的。

// org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)publicObjectgetProxy(@NullableClassLoaderclassLoader) {
returncreateAopProxy().getProxy(classLoader);
}

在这个方法中,通过createAopProxy方法获取了一个 AopProxy,然后通过 AopProxy 的getProxy方法来完成了代理对象的创建。我们看一下createAopProxy方法。

protectedfinalsynchronizedAopProxycreateAopProxy() {
if (!this.active) {
activate();
   }
returngetAopProxyFactory().createAopProxy(this);
}

可以看到,AopProxy 是通过getAopProxyFactory方法获取到的 AopProxyFactory 调用createAopProxy方法创建的。我们再进入getAopProxyFactory方法查看。

publicAopProxyFactorygetAopProxyFactory() {
returnthis.aopProxyFactory;
}

这里的 AopProxyFactory 其实就是成员变量aopProxyFactory,在之前的分析中,我们知道了,这里的aopProxyFactory是在 ProxyCreatorSupport 的构造方法中初始化的,它的类型是 DefaultAopProxyFactory。回到上面的createAopProxy方法中,我们再看 ProxyCreatorSupport 的createAopProxy方法。

代理创建方式的选择

// org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy@OverridepublicAopProxycreateAopProxy(AdvisedSupportconfig) throwsAopConfigException {
if (config.isOptimize() ||config.isProxyTargetClass() ||hasNoUserSuppliedProxyInterfaces(config)) {
Class<?>targetClass=config.getTargetClass();
if (targetClass==null) {
thrownewAopConfigException("TargetSource cannot determine target class: "+"Either an interface or a target is required for proxy creation.");
      }
if (targetClass.isInterface() ||Proxy.isProxyClass(targetClass)) {
returnnewJdkDynamicAopProxy(config);
      }
returnnewObjenesisCglibAopProxy(config);
   }
else {
returnnewJdkDynamicAopProxy(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#hasNoUserSuppliedProxyInterfacesprivatebooleanhasNoUserSuppliedProxyInterfaces(AdvisedSupportconfig) {
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 接口中定义的方法。

image.png

这个方法的代码分析,包含了以上两个类型中该方法的原理,我会放到下一篇文章中分析。

总结

本文进入createProxy方法,分析了 Spring 创建代理对象的大致过程,以及如何选择 JDK 动态代理或者 CGLIB 方式来创建代理对象。下一篇讲分析这两种方式创建代理的过程。

目录
相关文章
|
1月前
|
Java Spring
Spring5源码(38)-SpringAop代理调用过程(二)
Spring5源码(38)-SpringAop代理调用过程(二)
31 0
|
1月前
|
Java Spring
Spring5源码(37)-SpringAop代理调用过程(一)
Spring5源码(37)-SpringAop代理调用过程(一)
26 0
|
2天前
|
Java Spring
深入解析Spring源码,揭示JDK动态代理的工作原理。
深入解析Spring源码,揭示JDK动态代理的工作原理。
8 0
|
1月前
|
前端开发 Java 编译器
详解Spring与JDK注入
依赖注入是Spring框架的核心概念之一,它通过将对象之间的依赖关系外部化,实现了松耦合和可测试性。面向切面编程则允许开发人员将横切关注点(如日志、事务管理)从应用程序的主要业务逻辑中分离出来,以提高代码的模块化和可维护性。
26 4
|
1月前
|
设计模式 安全 Java
深入理解Spring Boot AOP:CGLIB代理与JDK动态代理的完全指南
深入理解Spring Boot AOP:CGLIB代理与JDK动态代理的完全指南
617 1
|
Java 程序员 索引
Spring的三种创建方式和各种属性的注入(二)
Spring的三种创建方式和各种属性的注入(二)
110 0
Spring的三种创建方式和各种属性的注入(二)
|
1月前
|
Java 应用服务中间件 Maven
SpringBoot 项目瘦身指南
SpringBoot 项目瘦身指南
81 0
|
1月前
|
Java 测试技术 Spring
Spring Boot 基于 JUnit 5 实现单元测试
Spring Boot 基于 JUnit 5 实现单元测试
55 0
|
1月前
|
存储 JSON Java
SpringBoot集成AOP实现每个接口请求参数和返回参数并记录每个接口请求时间
SpringBoot集成AOP实现每个接口请求参数和返回参数并记录每个接口请求时间
69 2
|
1月前
|
前端开发 Java 应用服务中间件
Springboot对MVC、tomcat扩展配置
Springboot对MVC、tomcat扩展配置