当前位置: 首页 > 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;}}

         

http://www.lryc.cn/news/388961.html

相关文章:

  • Linux[高级管理]——Squid代理服务器的部署和应用(传统模式详解)
  • 使用Vue 2 + Element UI搭建后台管理系统框架实战教程
  • Carla安装教程
  • 【PYG】处理Cora数据集分类任务使用的几个函数log_softmax,nll_loss和argmax
  • Labview绘制柱状图
  • 使用Python实现一个简单的密码管理器
  • 【云原生】服务网格(Istio)如何简化微服务通信
  • spring boot 整合 sentinel
  • 蜜雪冰城小程序逆向
  • pbootcms提交留言成功后跳转到指定的网址
  • 16、matlab求导、求偏导、求定积分、不定积分、数值积分和数值二重积分
  • MySQL 9.0创新版发布!功能又进化了!
  • 后端系统的安全性
  • .net 百度翻译接口核心类
  • 安卓应用开发学习:通过腾讯地图SDK实现定位功能
  • iptable精讲
  • 2024 年如何构建 AI 软件
  • Python实战,桌面小游戏,剪刀石头布
  • Hadoop权威指南-读书笔记-01-初识Hadoop
  • HttpServletResponse设置headers返回,发现headers中缺少“Content-Length“和“Content-Type“两个参数。
  • GraphPad Prism生物医学数据分析软件下载安装 GraphPad Prism轻松绘制各种图表
  • 7/1 uart
  • zdppy_api+vue3+antd开发前后端分离的预加载卡片实战案例
  • 别小看手机导航,这些隐藏功能大部分人可能都不知道
  • Lua实现链表(面向对象应用)
  • 每隔一个小时gc一次的问题
  • VBA数据库解决方案第十二讲:如何判断数据库中数据表是否存在
  • 五、Spring IoCDI ★ ✔
  • 计算机网络八股文
  • 科普文:一文搞懂jvm原理(四)运行时数据区