当前位置: 首页 > news >正文

Spring Boot 中的 AOP,到底是 JDK 动态代理还是 Cglib 动态代理

大家都知道,AOP 底层是动态代理,而 Java 中的动态代理有两种实现方式:

  • 基于 JDK 的动态代理

  • 基于 Cglib 的动态代理

这两者最大的区别在于基于 JDK 的动态代理需要被代理的对象有接口,而基于 Cglib 的动态代理并不需要被代理对象有接口。

那么,Spring 中的 AOP 是怎么实现的?是基于 JDK 的动态代理还是基于 Cglib 的动态代理?

1. Spring

先来说结论,Spring 中的动态代理,具体用哪种,分情况:

  • 如果代理对象有接口,就用 JDK 动态代理,否则就是 Cglib 动态代理。

  • 如果代理对象没有接口,那么就直接是 Cglib 动态代理。

来看看这段来自官方文档的说辞:

可以看到,即使在最新版的 Spring 中,依然是如上策略不变。即能用 JDK 做动态代理就用 JDK,不能用 JDK 做动态代理就用 Cglib,即首选 JDK 做动态代理。

2. Spring Boot 

Spring Boot 和 Spring 一脉相承,那么在动态代理这个问题上是否也是相同的策略呢?抱歉,这个还真不一样。

Spring Boot 中对这个问题的处理,以 Spring Boot2.0 为节点,前后不一样。

在 Spring Boot2.0 之前,关于 Aop 的自动化配置代码是这样的(Spring Boot 1.5.22.RELEASE):

@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {@Configuration@EnableAspectJAutoProxy(proxyTargetClass = false)@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",matchIfMissing = true)public static class JdkDynamicAutoProxyConfiguration {}@Configuration@EnableAspectJAutoProxy(proxyTargetClass = true)@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",matchIfMissing = false)public static class CglibAutoProxyConfiguration {}}

可以看到,这个自动化配置主要是在讨论 application.properties 配置文件中的 spring.aop.proxy-target-class 属性的值。

具体起作用的是 @ConditionalOnProperty 注解,关于这个注解中的几个属性,也来稍微说下:

  • prefix:配置文件的前缀。

  • name:配置文件的名字,和 prefix 共同组成配置的 key。

  • having:期待配置的值,如果实际的配置和 having 的值相同,则这个配置就会生效,否则不生效。

  • matchIfMissing:如果开发者没有在 application.properties 中进行配置,那么这个配置类是否生效。

基于如上介绍,很容易看出:

  • 如果开发者设置了 spring.aop.proxy-target-class 为 false,则使用 JDK 代理。

  • 如果开发者设置了 spring.aop.proxy-target-class 为 true,则使用 Cglib 代理。

  • 如果开发者一开始就没配置 spring.aop.proxy-target-class 属性,则使用 JDK 代理。

这是 Spring Boot 2.0 之前的情况。

再来看看 Spring Boot 2.0(含)之后的情况(Spring Boot 2.0.0.RELEASE):

@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class,AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {@Configuration@EnableAspectJAutoProxy(proxyTargetClass = false)@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)public static class JdkDynamicAutoProxyConfiguration {}@Configuration@EnableAspectJAutoProxy(proxyTargetClass = true)@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)public static class CglibAutoProxyConfiguration {}}

可以看到,大部分配置都是一样的,有一个地方不太相同,那就是 matchIfMissing 属性的值。可以看到,从 Spring Boot2.0 开始,如果用户什么都没有配置,那么默认情况下使用的是 Cglib 代理。

3. 实践

最后可以写一个简单的例子验证一下上面的理论。

首先创建一个 Spring Boot 项目(本案例使用最新版 Spring Boot,即默认使用 Cglib 代理),加入三个依赖即可,如下:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

接下来创建一个 IUserService 接口,如下:

public interface IUserService {void hello();}

然后再来创建一个该接口的实现类:

@Service
public class UserServiceImpl implements IUserService {@Overridepublic void hello() {}}

方法不用实现。

再来一个简单的切面:

@Aspect
@Component
@EnableAspectJAutoProxy
public class LogAspect {@Before("execution(* org.lzx.demo.UserServiceImpl.*(..))")public void before(JoinPoint jp) {System.out.println("jp.getSignature().getName() = " + jp.getSignature().getName());}}

最后再来一个简单的测试方法,注入 IUserService 实例:

@RestController
public class HelloController {@Autowiredprivate IUserService iUserService;@GetMapping("/hello")public void hello() {iUserService.hello();}}

DBUEG 运行一下,就可以看到 IUserService 是通过 Cglib 来代理的。

如果我们想用 JDK 来代理,那么只需要在 application.properties 中添加如下配置即可:

spring.aop.proxy-target-class=false

添加完成后,重新 DEBUG,如下图:

可以看到,已经使用了 JDK 动态代理了。

如果用的是 Spring Boot 1.5.22.RELEASE 这个版本,那么即使不在 application.properties 中添加配置,默认也是 JDK 代理。 

4. 小结

总结一下:

  1. Spring 中的 AOP,有接口就用 JDK 动态代理,没有接口就用 Cglib 动态代理。

  2. Spring Boot 中的 AOP,2.0 之前和 Spring 一样;2.0 之后首选 Cglib 动态代理,如果用户想要使用 JDK 动态代理,需要自己手动配置。

相关文章:

Spring Boot 中的 AOP,到底是 JDK 动态代理还是 Cglib 动态代理

大家都知道&#xff0c;AOP 底层是动态代理&#xff0c;而 Java 中的动态代理有两种实现方式&#xff1a; 基于 JDK 的动态代理 基于 Cglib 的动态代理 这两者最大的区别在于基于 JDK 的动态代理需要被代理的对象有接口&#xff0c;而基于 Cglib 的动态代理并不需要被代理对…...

记录一下在工作中使用 LayUI bug的问题

前言&#xff1a; LayUI是一个很老的框架了&#xff0c;经常会碰到一些 bug。不过由于他的轻量级&#xff0c;仍然有一些项目在使用。解决这些 bug 可能会对大家产生一些意义。 layui中 slect form表单元素 不美化显现的问题 layui中美化的表单元素 在渲染完成要添加 form.re…...

手机自动无人直播,实景无人直播真的有用吗?

继数字人直播之后&#xff0c;手机自动直播开始火热了起来&#xff0c;因为其门槛低&#xff0c;成本低&#xff0c;一部手机一个账号就可以实现直播&#xff0c;一时深受广大商家的好评。那么&#xff0c;手机自动无人直播究竟是如何实现自动直播的呢&#xff1f; 在传统的直…...

python 面试题--2(15题)

目录 1.解释Python中的 GIL&#xff08;全局解释器锁&#xff09;是什么&#xff0c;它对多线程编程有什么影响&#xff1f; 2.Python中的装饰器是什么&#xff1f;如何使用装饰器&#xff1f; 3.解释Python中的迭代器和生成器的区别。 4.什么是Python中的列表解析&#xf…...

kafka复习:(11)auto.offset.reset的默认值

在ConsumerConfig这个类中定义了这个属性的默认值&#xff0c;如下图 也就是默认值为latest,它的含义是&#xff1a;如果没有客户端提交过offset的话&#xff0c;当新的客户端消费时&#xff0c;把最新的offset设置为当前消费的offset. 默认是自动提交位移的&#xff0c;每5秒…...

【javaweb】学习日记Day7 - Mysql 数据库 DQL 多表设计

之前学习过的SQL语句笔记总结戳这里→【数据库原理与应用 - 第六章】T-SQL 在SQL Server的使用_Roye_ack的博客-CSDN博客 目录 一、DQL 数据查询 1、基本查询 2、条件查询 3、分组查询 &#xff08;1&#xff09;聚合函数 ① count函数 ② max min avg sum函数 &…...

线程的生命周期

线程的生命周期 与人有生老病死一样&#xff0c;线程也同样要经历开始&#xff08;等待&#xff09;、运行、挂起和停止四种不同的状态。这四种状态都可以通过Thread类中的方法进行控制。下面给出了Thread类中和这四种状态相关的方法。 // 开始线程 public void start( ); …...

GAN | 论文精读 Generative Adversarial Nets

提出一个GAN &#xff08;Generative Adversarial Nets&#xff09; 1 方法 &#xff08;1&#xff09;生成模型G&#xff08;Generative&#xff09;&#xff0c;是用来得到分布的&#xff0c;在统计学眼里&#xff0c;整个世界是通过采样不同的分布得到的&#xff0c;生成…...

Yolo系列-yolov2

YOLO-V2 更快&#xff01;更强&#xff01; YOLO-V2-BatchNormalization BatchNormalization&#xff08;批归一化&#xff09;是一个常用的深度神经网络优化技术&#xff0c;它可以将输入数据进行归一化处理&#xff0c;使得神经网络更容易进行学习。在YOLOv2中&#xff0c;B…...

Linux下的系统编程——vim/gcc编辑(二)

前言&#xff1a; 在Linux操作系统之中有很多使用的工具&#xff0c;我们可以用vim来进行程序的编写&#xff0c;然后用gcc来生成可执行文件&#xff0c;最终运行程序。下面就让我们一起了解一下vim和gcc吧 目录 一、vim编辑 1.vim的三种工作模式 2.基本操作之跳转字符 &a…...

2023年国赛 高教社杯数学建模思路 - 案例:最短时间生产计划安排

文章目录 0 赛题思路1 模型描述2 实例2.1 问题描述2.2 数学模型2.2.1 模型流程2.2.2 符号约定2.2.3 求解模型 2.3 相关代码2.4 模型求解结果 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 最短时…...

芯科科技推出专为Amazon Sidewalk优化的全新片上系统和开发工具,加速Sidewalk网络采用

芯科科技为Sidewalk开发提供专家级支持 中国&#xff0c;北京 - 2023年8月22日 – 致力于以安全、智能无线连接技术&#xff0c;建立更互联世界的全球领导厂商Silicon Labs&#xff08;亦称“芯科科技”&#xff0c;NASDAQ&#xff1a;SLAB&#xff09;今日在其一年一度的第四…...

Kotlin 丰富的函数特性

Kotlin 是一门基于 JVM 的现代编程语言&#xff0c;它提供了丰富的函数特性&#xff0c;使得编写简洁、灵活且可读性强的代码成为可能。以下是 Kotlin 函数的一些主要特性&#xff1a; 一、函数声明与调用 在 Kotlin 中&#xff0c;使用 fun 关键字来声明函数。函数声明的基本…...

Node.js怎么搭建HTTP服务器

在 Node.js 中搭建一个简单的 HTTP 服务器非常容易。以下是一个基本的示例&#xff0c;演示如何使用 Node.js 创建一个简单的 HTTP 服务器&#xff1a; // 导入 http 模块 const http require(http); // 创建一个 HTTP 服务器 const server http.createServer((req, res) …...

基于Redisson的联锁(MultiLock)

基于Redis的分布式MultiLock对象允许对Lock对象进行分组并将它们作为单个锁进行处理。每个RLock对象可能属于不同的Redisson实例。 如果获取的Redisson实例MultiLock崩溃&#xff0c;那么它可能永远挂在获取状态。为了避免这种情况&#xff0c;Redisson维护了一个锁看门狗&…...

人脸识别平台批量导入绑定设备的一种方法

因为原先平台绑定设备是通过一个界面进行人工选择绑定或一个人一个人绑定设备。如下&#xff1a; 但有时候需要在几千个里选择出几百个&#xff0c;那这种方式就不大现实了&#xff0c;需要另外一种方法。 目前相到可以通过导入批量数据进行绑定的方式。 一、前端 主要是显示…...

MySQL—MySQL的NULL值是怎么存放的

一、引言 1、MySQL数据存放在哪个文件&#xff1f; 创建一个数据库会产生三种格式的文件&#xff0c;分别是.opt格式、.frm格式、.ibd格式。 opt格式&#xff1a;用来存储当前数据库的默认字符集和字符校验规则。 frm格式&#xff1a;该文件是用来保存每个表的元数据信息的&…...

sql server删除历史数据

1 函数 datediff函数: DATEDIFF ( datepart , startdate , enddate )datepart的取值可以是year,quarter,Month,dayofyear,Day,Week,Hour,minute,second,millisecond startdate 是从 enddate 减去。如果 startdate 比 enddate 晚&#xff0c;返回负值。 2 例子 删除2023年以…...

目标检测项目中,使用python+xml.etree.ElementTree修改xml格式标注文件中的类别名称

需求&#xff1a; 数据集的数据增强中&#xff0c;有时需要将xml标注文件中的类别做修改为新类别&#xff0c;或者将几个类别合并为一个类别。 解决方法&#xff1a; 使用pythonimport xml.etree.ElementTree将xml标注文件中的类别名称做修改。代码如下&…...

最新域名和子域名信息收集技术

域名信息收集 1&#xff0e;WHOIS查询 WHOIS是一个标准的互联网协议&#xff0c;可用于收集网络注册信息、注册域名﹑IP地址等信息。简单来说&#xff0c;WHOIS就是一个用于查询域名是否已被注册及注册域名详细信息的数据库&#xff08;如域名所有人、域名注册商&#xff09;…...

C语言基础之——指针(上)

前言&#xff1a;小伙伴们又见面啦&#xff01;本期内容&#xff0c;博主将展开讲解有关C语言中指针的上半部分基础知识&#xff0c;一起学习起来叭&#xff01;&#xff01;&#xff01; 目录 一.什么是指针 二.指针类型 1.指针的解引用 2.指针-整数 三.野指针 1.野指针…...

构建 NodeJS 影院预订微服务并使用 docker 部署(04/4)

一、说明 构建一个微服务的电影网站&#xff0c;需要Docker、NodeJS、MongoDB&#xff0c;这样的案例您见过吗&#xff1f;如果对此有兴趣&#xff0c;您就继续往下看吧。 我们前几章的快速回顾 第一篇文章介绍了微服务架构模式&#xff0c;并讨论了使用微服务的优缺点。第二篇…...

SpringBootWeb案例 Part3

目录 1. 新增员工 1.1 需求 1.2 接口文档 1.3 思路分析 PostMapping RequestBody //把前端传递的JSON数据填充到实体类中 1.4 功能开发 1.5 功能测试 1.6 前后端联调 2. 文件上传 2.1 文件上传简介 Spring中提供了一个API&#xff1a;MultipartFile&#xff0c;使…...

C++中using 用法

C中的 using 关键字用于引入命名空间、类型别名和模板别名。以下是 using 关键字的几种常见用法及其中文解析&#xff1a; 1. 引入命名空间&#xff1a; using namespace std; 中文解析&#xff1a;引入 std 命名空间&#xff0c;使得命名空间中的成员在当前作用域内可直接使…...

window下jdk安装及更换jdk版本的一些问题。

目录 jdk安装jdk的选择。oracle的jdk怎么安装。openjdk怎么安装。 jdk的版本控制。更换jdk的一些问题。 jdk安装 jdk的选择。 目前有两种可选的jdk&#xff0c;oracle的和开源的Openjdk&#xff0c;这两种jdk的区别可以自行查阅&#xff0c;就结果而言&#xff0c;openjdk开源…...

GPT4模型架构的泄漏与分析

迄今为止&#xff0c;GPT4 模型是突破性的模型&#xff0c;可以免费或通过其商业门户&#xff08;供公开测试版使用&#xff09;向公众提供。它为许多企业家激发了新的项目想法和用例&#xff0c;但对参数数量和模型的保密却扼杀了所有押注于第一个 1 万亿参数模型到 100 万亿参…...

GEE/PIE遥感大数据处理与典型案例丨数据整合Reduce、云端数据可视化、数据导入导出及资产管理、机器学习算法等

目录 ​专题一&#xff1a;初识GEE和PIE遥感云平台 专题二&#xff1a;GEE和PIE影像大数据处理基础 专题三&#xff1a;数据整合Reduce 专题四&#xff1a;云端数据可视化 专题五&#xff1a;数据导入导出及资产管理 专题六&#xff1a;机器学习算法 专题七&#xff1a;…...

STM32--DMA

文章目录 DMA简介DMA特性 DMA框图DMA基本结构DMA请求数据宽度对齐DMA数据转运工程DMAADC多通道 DMA简介 直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预&#xff0c;数据可以通过DMA快速地移动&#xff0c;这就节省了CPU的…...

mongodb和redis的用途

MongoDB和Redis都是常见的NoSQL数据库&#xff0c;它们有不同的特点和用途。 MongoDB的主要特点和用途&#xff1a; 数据存储&#xff1a;MongoDB是一种面向文档的数据库&#xff0c;以JSON样式的BSON文档&#xff08;二进制JSON&#xff09;的形式存储数据。它支持复杂的数据…...

【动手学深度学习】--18.图像增广

文章目录 图像增广1.常用的图像增广方法1.1翻转和裁剪1.2改变颜色1.3结合多种图像增广方法 2.使用图像增广进行训练3.训练 图像增广 官方笔记&#xff1a;图像增广 学习视频&#xff1a;数据增广【动手学深度学习v2】 图像增广在对训练图像进行一系列的随机变化之后&#xff…...

有什么网站做任务换q币吗/游戏推广赚佣金

此教程是博主亲自帮朋友管理服务器所操作的完整步骤&#xff0c;当然此步骤适合所有的linux-centos系统&#xff0c;不管centos怎么变&#xff0c;linux怎么变&#xff0c;它的这些命令可以说是基本不变的&#xff1b;先说一下博主此教程所用的服务器的环境&#xff1a; 操作系…...

导入表格数据做地图网站/网站推广哪家好

---------------------------------------------------------------------------------------- 转载于:https://www.cnblogs.com/xioxu/archive/2008/09/23/1297518.html...

这样做网站/百度建站

Ruby中的字符串处理非常灵活"abc"[0] 返回97 就是a"abc"[1] 98"abc"[2] 99"abc"[3] nil"abc"[-1] 99 从后向前数"abc"[-2] 98"abc"[-3] 97"abc"[-4] nil"abc" * 2 返回"abca…...

厦门做商城网站/东莞网络优化哪家公司好

本文讲的是众信金融开设债权转让增加用户理财热情,余额宝自横空出世以来&#xff0c;仅半年多时间便打造出网民投身互联网理财的热潮&#xff0c;除享受远高于银行的年化收益外&#xff0c;深受网民喜爱的还有一条便是“T0”赎回&#xff0c;恰恰满足投资者对产品流动性的需求。…...

网站建设案例 算命网站/搜狗seo刷排名软件

做过一个小项目&#xff0c;其中实现了摇一摇功能和刮一刮功能还有播放背景音乐等 摇一摇功能主要用到加速度传感器&#xff1a;Sensor.TYPE_ACCELEROMETER 摇一摇功能主要是监听手机加速度变化&#xff0c;当超过设定的某一值时&#xff0c;即触发事件。 12345678910111213141…...

电子书网站怎么做/接app推广的单子在哪接

前提&#xff1a;使用python3一&#xff1a;Django连接MySQL时默认使用MySQLdb驱动&#xff0c;但MySQLdb不支持Python3&#xff0c;因此这里将MySQL驱动设置为pymysql。具体步骤如下&#xff1a;(1)使用 pip install pymysql 进行安装(2)在项目目录下的__init__.py文件中添加以…...