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

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;}}

         

相关文章:

  • 【Spring Boot 源码学习】初识 ConfigurableEnvironment
  • 数据结构(3.8)——栈的应用
  • gdb调试命令大全
  • 【产品经理】订单处理11-订单修改场景梳理
  • 泛微开发修炼之旅--29用计划任务定时发送邮件提醒
  • RISC-V在当前计算架构中的地位
  • 使用Vue CLI方式创建Vue3.0应用程序
  • 如何在Java项目中实现领域驱动设计(DDD)
  • 2024华为OD机试真题-找数字-(C++/Python)-C卷D卷-200分
  • 【BUUCTF-PWN】7-[第五空间2019 决赛]PWN5
  • 【大模型LLM面试合集】大语言模型基础_激活函数
  • 金斗云 HKMP智慧商业软件 任意用户创建漏洞复现
  • 《Windows API每日一练》6.2 客户区鼠标消息
  • 【Java09】方法(下)
  • 免费办公软件 -- LibreOffice v24.2.4
  • 《剑指offer》分解让复杂问题更简单
  • 【跃迁之路】【733天】程序员高效学习方法论探索系列(实验阶段490-2019.2.23)...
  • Android开源项目规范总结
  • CSS实用技巧干货
  • E-HPC支持多队列管理和自动伸缩
  • Java 最常见的 200+ 面试题:面试必备
  • java中具有继承关系的类及其对象初始化顺序
  • MySQL QA
  • Spring框架之我见(三)——IOC、AOP
  • swift基础之_对象 实例方法 对象方法。
  • SwizzleMethod 黑魔法
  • VuePress 静态网站生成
  • 安卓应用性能调试和优化经验分享
  • 编写符合Python风格的对象
  • 前嗅ForeSpider中数据浏览界面介绍
  • 使用API自动生成工具优化前端工作流
  • 通过来模仿稀土掘金个人页面的布局来学习使用CoordinatorLayout
  • 我是如何设计 Upload 上传组件的
  • 协程
  • 一个完整Java Web项目背后的密码
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • 优化 Vue 项目编译文件大小
  • 原生 js 实现移动端 Touch 滑动反弹
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • PostgreSQL之连接数修改
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • # 达梦数据库知识点
  • # 消息中间件 RocketMQ 高级功能和源码分析(七)
  • #每天一道面试题# 什么是MySQL的回表查询
  • #周末课堂# 【Linux + JVM + Mysql高级性能优化班】(火热报名中~~~)
  • (C语言)输入自定义个数的整数,打印出最大值和最小值
  • (WSI分类)WSI分类文献小综述 2024
  • (分布式缓存)Redis哨兵
  • (附源码)spring boot网络空间安全实验教学示范中心网站 毕业设计 111454
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • (附源码)springboot助农电商系统 毕业设计 081919
  • (论文阅读26/100)Weakly-supervised learning with convolutional neural networks
  • (原创) cocos2dx使用Curl连接网络(客户端)
  • (转)h264中avc和flv数据的解析
  • ./configure,make,make install的作用