Spring Boot 学习第八天:AOP代理机制对性能的影响

1 概述

        在讨论动态代理机制时,一个不可避免的话题是性能。无论采用JDK动态代理还是CGLIB动态代理,本质上都是在原有目标对象上进行了封装和转换,这个过程需要消耗资源和性能。而JDK和CGLIB动态代理的内部实现过程本身也存在很大差异。下面将讨论两种动态代理机制对系统运行性能所带来的影响。

2 测试案例设计

        为了量化不同动态代理对性能的影响程度,将设计一个案例,在该案例中同样使用前面介绍的AccountService接口以及它的实现类AccountServiceImpl。将通过创建一定数量的AccountServiceImpl实例并调用它的doAccountTransaction()方法,触发动态代理机制。

        为了能够基于不同的代理机制来创建对象,需要引入Spring中一个非常有用的注解,即@Scope。这个注解可以用来设置Bean的作用域,还可以用来指定代理模式ScopedProxyMode,在Spring中,ScopedProxyMode是一个枚举,代码如下:

public enum ScopedProxyMode {DEFAULT,NO,INTERFACES,TARGET_CLASS;private ScopedProxyMode() {}
}

        这里的INTERFACES代表的就是JDK动态代理,而TARGET_CLASS使用的则是CGLIB动态代理。现在,创建两个配置类JDKProxyConfig和CGLIBProxyConfig,分别针对AccountServiceImpl指定两种不同的代理机制。JDKProxyConfig代码如下:

@Configuration
@EnableAspectJAutoProxy
public class JDKProxyConfig {@Bean@Scope(proxyMode = ScopedProxyMode.INTERFACES)public AccountService accountService(){return new AccountServiceImpl();}
}

        CGLIBProxyConfig代码如下:

@EnableAspectJAutoProxy
@Configuration
public class CGLIBProxyConfig {@Bean@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)public AccountService accountService(){return new AccountServiceImpl();}
}

        借助于这两个配置类,就可以通过AnnotationConfigApplicationContext这个基于注解配置的应用上下文对象来获取添加了不同代理机制的AccountServiceImpl对象。准备工作已经完成,编写一个测试用例来对不同代理机制的性能进行量化。代码如下:

public class ProxyTest {private static final Logger LOGGER = Logger.getLogger(ProxyTest.class);@Testpublic void testAopProxyPerformance() throws MinimumAccountException {int countObjects = 5000;AccountServiceImpl[] unproxiedClasses = new AccountServiceImpl[countObjects];for (int i = 0; i < countObjects; i++) {unproxiedClasses[i] = new AccountServiceImpl();}AccountService[] cglibProxyClasses = new AccountService[countObjects];AccountService accountService = null;for (int i = 0; i < countObjects; i++) {accountService = new AnnotationConfigApplicationContext(CGLIBProxyConfig.class).getBean(AccountService.class);cglibProxyClasses[i] = accountService;}AccountService[] jdkProxyClasses = new AccountService[countObjects];for (int i = 0; i < countObjects; i++) {accountService = new AnnotationConfigApplicationContext(JDKProxyConfig.class).getBean(AccountService.class);jdkProxyClasses[i] = accountService;}long noProxy = invokeTargetObjects(countObjects, unproxiedClasses);displayResults("NOProxy",noProxy);long jdkProxy = invokeTargetObjects(countObjects, jdkProxyClasses);displayResults("JDKProxy",jdkProxy);long cglibProxy = invokeTargetObjects(countObjects, cglibProxyClasses);displayResults("cglibProxy",cglibProxy);}private void displayResults(String label, long timeTook) {LOGGER.info(label + ": " + timeTook + "(ns) " + (timeTook / 1000000) + "(ms)");}private long invokeTargetObjects(int countObjects,AccountService[] classes) throws MinimumAccountException {long start = System.nanoTime();Account source = new Account(101,"Account1");Account dest = new Account(102,"Account2");for (int i = 0; i < countObjects; i++) {classes[i].doAccountTransaction(source, dest, 100);}long end = System.nanoTime();return end - start;}
}

        运行结果:

        可以看到,分别针对不使用代理、使用JDK代理和CGLIB代理的场景,创建了5000个AccountServiceImpl对象实例,并记录它们的创建时间。以上量化结果取决于不同的机器配置,但不影响得出结论。从结果中不难看出,JDK动态代理在性能上优于CGLIB动态代理,但相差并不大。 

  其他类的代码如下:

public class Account {private String accountName;private Integer accountNumber;public String getAccountName() {return accountName;}public void setAccountName(String accountName) {this.accountName = accountName;}public Integer getAccountNumber() {return accountNumber;}public void setAccountNumber(Integer accountNumber) {this.accountNumber = accountNumber;}public Account(Integer accountNumber, String accountName) {this.accountNumber = accountNumber;this.accountName = accountName;}
}
public interface AccountService {boolean doAccountTransaction(Account source, Account dest, int amount);
}
public class AccountServiceImpl implements AccountService {@Overridepublic boolean doAccountTransaction(Account source, Account dest, int amount) {return true;}}

         

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/365521.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

StaleElementReferenceException 不再是问题:Google Colab 上的 Selenium 技巧

背景介绍 在现代网页数据抓取领域&#xff0c;Selenium 是一款强大的工具&#xff0c;它使得自动化浏览和数据提取变得异常简单。然而&#xff0c;当面对动态页面时&#xff0c;许多爬虫开发者常常会遇到一个令人头疼的问题——StaleElementReferenceException。这一异常的出现…

MTK7621:交换芯片工作队列

mt7530交换芯片的数据接收中断后,把具体接收数据工作任务、委托到workqueue队列中,让内核work_thread()线程任务来处理,这部分内容请参考《workqueue工作原理》中的描述。 workqueue基本工作流程框架如下: 框架业务关系: 1,程序把work单加入到workqueue中,就等于把工…

java 操作 milvus 2.1.4

1. 确认 docker 运行的 milvus容器镜像版本情况&#xff1a; 2. pom 依赖&#xff1a; <dependency><groupId>io.milvus</groupId><artifactId>milvus-sdk-java</artifactId><version>2.1.0</version><exclusions><exclusi…

压缩包怎么解压,解压压缩包不损坏文件

常见格式&#xff1a; ZIP&#xff1a;最常见的压缩文件格式之一&#xff0c;支持跨平台。RAR&#xff1a;另一种常见的压缩文件格式&#xff0c;通常压缩率比ZIP高&#xff0c;但不如ZIP普及。7Z&#xff1a;来自7-Zip的压缩格式&#xff0c;支持更高的压缩率和一些高级特性。…

使用Python绘制太阳系图

使用Python绘制太阳系图 太阳系图太阳系图的优点使用场景 效果代码 太阳系图 太阳系图&#xff08;Sunburst Chart&#xff09;是一种层次结构图表&#xff0c;用于表示数据的分层结构。它使用同心圆表示各个层级&#xff0c;中心圆代表最高层级&#xff0c;向外的圆环代表逐级…

[数据集][目标检测]井盖未盖好检测数据集VOC+YOLO格式20123张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;20123 标注数量(xml文件个数)&#xff1a;20123 标注数量(txt文件个数)&#xff1a;20123 标…

WDG看门狗

1 WDG 1.1 简介 WDG是看门狗定时器&#xff08;Watchdog Timer&#xff09;的缩写&#xff0c;它是一种用于计算机和嵌入式系统中的定时器&#xff0c;用来检测和恢复系统故障。 看门狗就像是一个忠诚的宠物狗&#xff0c;它时刻盯着你的程序&#xff0c;确保它们正常运行。…

Apache ZooKeeper 简介

介绍 Apache ZooKeeper 是一种分布式协调服务&#xff0c;旨在管理和同步大量分布式应用程序。ZooKeeper 是 Apache 软件基金会下的一个开源项目&#xff0c;它解决了维护分布式应用程序的配置信息、命名、分布式同步和组服务的复杂性。本文探讨了 ZooKeeper 的架构、功能、应…

python 压缩数据

requests 是 Python 中一个非常流行的 HTTP 库&#xff0c;用于发送各种 HTTP 请求。下面是一个使用 requests 库发送简单 GET 请求和 POST 请求的示例&#xff1a; 首先&#xff0c;确保你已经安装了 requests 库。如果还没有安装&#xff0c;可以使用 pip 进行安装&#xff…

深入浅出:npm 常用命令详解与实践

在现代的前端开发流程中&#xff0c;npm&#xff08;Node Package Manager&#xff09;已经成为了不可或缺的一部分。它不仅帮助我们有效地管理项目中的依赖包&#xff0c;还提供了一系列强大的命令来优化开发体验。在这篇博客中&#xff0c;我们将深入探讨 npm 的常用命令&…

[数据集][目标检测]游泳者溺水检测数据集VOC+YOLO格式4599张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4599 标注数量(xml文件个数)&#xff1a;4599 标注数量(txt文件个数)&#xff1a;4599 标注…

React 打包时如何关闭源代码混淆

React 开发中&#xff0c;使用 npm build 命令进行生产代码打包&#xff0c;为了压缩代码并尽量保证代码的安全性&#xff0c;React 打包时会代码进行压缩和混淆&#xff0c;但是有时我们需要 debug 生产环境的源代码&#xff0c;例如当我们调试 SSR 的项目时&#xff0c;需要禁…

ThreeJS-3D教学十二:ShaderMaterial

一、首先 Shader 是做什么的 Shader 可以自定义每个顶点、每个片元/像素如何显示&#xff0c;而控制顶点和片元显示是通过设置 vertexShader 顶点着色器和 fragmentShader 片元着色器&#xff0c;这两个着色器用在 ShaderMaterial 和 RawShaderMaterial 材质上。 我们先看一个例…

容器技术-docker5

一、docker-compose 常用命令和指令 1. 概要 默认的模板文件是 docker-compose.yml&#xff0c;其中定义的每个服务可以通过 image 指令指定镜像或 build 指令&#xff08;需要 Dockerfile&#xff09;来自动构建。 注意如果使用 build 指令&#xff0c;在 Dockerfile 中设置…

从零开始三天学会微信小程序开发(三)

看到不少入门的小程序开发者不断的问重复性的问题&#xff0c;我们从实战角度开发了这个课程&#xff0c;希望能够帮助大家了解小程序开发。 课程分三天&#xff1a; 第一天&#xff1a;微信小程序开发入门第二天&#xff1a;给小程序接入云端数据第三天&#xff1a;完善我的…

007-GeoGebra基础篇-构建等边三角形

今天继续来一篇尺规作图&#xff0c;可以跟着操作一波&#xff0c;刚开始我写的比较细一点&#xff0c;每步都有截图&#xff0c;后续内容逐渐复杂后我就只放置算式咯。 目录 一、先看看一下最终效果二、本次涉及的内容三、开始尺规画图1. 绘制定点A和B2. 绘制线段AB3. 以点A为…

企业互联网建站源码系统 附带完整的安装代码包以及搭建部署教程

系统概述 企业互联网建站源码吸系统是一款集众多先进功能于一身的建站工具。它提供了丰富的模板和组件&#xff0c;允许企业根据自身需求和品牌形象进行个性化定制&#xff0c;快速搭建出具有独特风格的网站。 代码示例 系统特色功能一览 1.用户友好界面&#xff1a;系统采用…

grpc学习golang版( 五、多proto文件示例 )

系列文章目录 第一章 grpc基本概念与安装 第二章 grpc入门示例 第三章 proto文件数据类型 第四章 多服务示例 第五章 多proto文件示例 第六章 服务器流式传输 第七章 客户端流式传输 第八章 双向流示例 文章目录 一、前言二、定义proto文件2.1 公共proto文件2.2 语音唤醒proto文…

git上传本地项目及更新项目

1、注册GitHub账号和下载git 2、在GitHub上新建一个仓库&#xff0c;点击号——>New repository&#xff0c;给仓库起一个名字&#xff0c;点击Create repository 3、进入要上传的项目中&#xff0c;右键点击git back here&#xff0c;命令行输入git init初始化&#xff0c…

socket编程常见操作

1、连接的建立 分为两种&#xff1a;服务端处理接收客户端的连接&#xff1b;服务端作为客户端连接第三方服务 //作为服务端 int listenfd socket(AF_INET, SOCK_STREAM, 0); bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) listen(listenfd, 10); //…