JVM-Sandbox--测试技术中引流回放的应用

news/2024/12/4 17:12:07/

关键点提炼

  • Sandbox简述原理:利用虚拟化技术创建隔离环境,利用字节码增强将被mock方法添加到隔离环境中;在被调用时Sandbox通过反射机制查找该方法,并使用代理对象将其转发给Sandbox中的虚拟机执行。当Sandbox执行完毕后,将结果返回给主程序。
  • 相关原理:了解类加载机制、反射机制、代理机制​​​​​​​。
  • 测试应用:引流回放-采集线上真实流量,在预防/测试环境中回放流量(mock中间件、DB等)来发现bug。


一、JVM-Sandbox是什么?

阿里的Jvm-Sandbox是一款Java应用沙箱,沙箱(Sandbox)是指一个隔离的环境,类似于一个封闭的盒子,可以在其中运行程序或应用,而不会影响到系统中其他部分的操作。在这个环境中,程序只能访问被授权的资源和功能,而不能访问其他系统资源。沙箱技术的目的是为了保护系统安全和稳定性,同时也可以提供更好的应用程序开发和测试环境。通过将程序隔离在一个独立的环境中,可以避免它访问到不该访问的资源和数据,从而降低了安全风险。

二、能解决什么问题?

  • 有时候突然一个问题反馈上来,需要入参才能完成定位,但恰恰没有任何日志,甚至出现在别人的代码里,好想开发一个工具可以根据需要动态添加日志,最好还能按照业务ID进行过滤。

  • 系统间的异常模拟可以使用的工具很多,可是系统内的异常模拟怎么办,加开关或是用AOP在开发系统中实现,好想开发一个更优雅的异常模拟工具,既能模拟系统间的异常,又能模拟系统内的异常。

  • 好想获取行调用链路数据,可以用它识别场景、覆盖率统计等等,覆盖率统计工具不能原生支持,统计链路数据不准确。想自己开发一个工具获取行链路数据。

  • 想开发录制回放、故障模拟、动态日志、行链路获取等等工具,就算我开发完成了,这些工具底层实现原理相同,同时使用,要怎么消除这些工具之间的影响,怎么保证这些工具动态加载,怎么保证动态加载/卸载之后不会影响其他工具,怎么保证在工具有问题的时候,快速消除影响,代码还原。

三、实现原理
Sandbox的实现原理主要依赖于Java的虚拟化技术和字节码增强技术。
首先,Sandbox利用Java的虚拟化技术,在同一进程内创建多个相互隔离的虚拟机(称为Isolate)。每个Isolate都有自己独立的类加载器、内存空间和线程池,可以在其中运行不同的Java应用程序,从而实现对应用程序之间的隔离。
然后,Sandbox利用Java字节码增强技术,对需要被Mock的类进行动态修改。具体来说,Sandbox会针对需要被Mock的类和方法,使用字节码增强工具生成一个新的类和方法,并将其添加到Sandbox的虚拟机中。这样,在Sandbox中就可以调用新的类和方法,从而实现Mock的功能。
最后,在Sandbox和主程序之间进行沟通交互时,Sandbox采用了基于Java反射和代理的方式。具体来说,当主程序需要调用Sandbox中的某个方法时,Sandbox通过反射机制查找该方法,并使用代理对象将其转发给Sandbox中的虚拟机执行。当Sandbox执行完毕后,将结果返回给主程序。
使用sandbox实现mock
常用的Mock框架有Mockito、EasyMock等。这些框架通常采用字节码增强或动态代理等技术,来实现对类和方法的Mock。

特点:

1. 隔离性:Sandbox可以将不同的Java应用程序隔离在不同的虚拟机中运行,避免应用程序之间相互影响和干扰。

2. 安全性:Sandbox可以对Java应用程序进行安全限制和监控,防止恶意代码的执行和攻击。

3. 轻量级:Sandbox采用轻量级的虚拟化技术,使得其开销比传统虚拟机更小。

4. 灵活性:Sandbox可以根据不同的需求定制不同的虚拟机环境,以满足不同的应用场景。

5. 高可靠性:Sandbox采用了多种技术手段来保证虚拟机的稳定性和可靠性,如快照、恢复等。

四、具体实现步骤:
1. 创建一个Sandbox环境,并在其中加载需要被Mock的类和方法。
2. 在Sandbox环境中创建一个Mock对象,并将其注册到主程序中。
3. 在主程序中调用Mock对象,由Mock对象返回预设的结果。
4. 在测试完成后,销毁Sandbox环境,释放资源。
需要注意的是,使用Sandbox实现Mock需要对Java虚拟机的运行机制、类加载机制、反射机制等有一定的了解和掌握。此外,由于Sandbox的性能开销较大,因此在实际使用中需要进行充分的测试和评估,以确保其不会对系统性能产生过大的影响。

五、实现代码

目标:Mock掉一个名为Calculator的类中的add方法

public class Calculator {public int add(int a, int b) {return a + b;}
}

1. 首先需要引入Sandbox的依赖库,并创建一个Sandbox环境:

创建了一个SandboxBuilder对象,并通过addClassPathEntry方法添加了需要被Mock类所在的jar包路径。然后,我们通过addTransferModel方法将需要被Mock的类和方法加入到Sandbox环境中


SandboxBuilder sandboxBuilder = new SandboxBuilder();
sandboxBuilder.addClassPathEntry("path/to/calculator.jar");
// 添加需要被Mock的类和方法
sandboxBuilder.addTransferModel(new TransferModel.Builder(Calculator.class.getName()).methodName("add").parameterTypes(int.class, int.class).build());
Sandbox sandbox = sandboxBuilder.buildSandbox();

2. 在Sandbox环境中创建Mock对象,并将其注册到主程序中:

通过sandbox.getObject方法在Sandbox环境中创建了一个Mock对象,并使用when.thenReturn方法预设了Mock对象的行为。然后,我们将该Mock对象注册到主程序中


// 创建Mock对象
Object mockObj = sandbox.getObject(Calculator.class.getName());
when(mockObj.add(1, 2)).thenReturn(3);
// 将Mock对象注册到主程序中
sandbox.getApplicationClassLoader().getTransletClasses().put(Calculator.class.getName(), mockObj.getClass());

3. 在主程序中调用Mock对象:

调用了Calculator类中的add方法,根据之前预设的Mock行为,此处应输出result: 3


Calculator calculator = new Calculator();
int result = calculator.add(1, 2);
System.out.println("result: " + result);

4. 在测试完成后销毁Sandbox环境:

sandbox.destroy();

完整代码:

实现了对Calculator类中的add方法进行Mock,并输出了结果。需要注意的是,由于Sandbox的性能开销较大,在实际使用时需要进行充分的测试和评估,以确保其不会对系统性能产生过大的影响

import com.alibaba.jvm.sandbox.api.Sandbox;
import com.alibaba.jvm.sandbox.api.SandboxBuilder;
import com.alibaba.jvm.sandbox.api.model.TransferModel;import static org.mockito.Mockito.*;public class MockWithSandboxDemo {public static void main(String[] args) {SandboxBuilder sandboxBuilder = new SandboxBuilder();sandboxBuilder.addClassPathEntry("path/to/calculator.jar");// 添加需要被Mock的类和方法sandboxBuilder.addTransferModel(new TransferModel.Builder(Calculator.class.getName()).methodName("add").parameterTypes(int.class, int.class).build());Sandbox sandbox = sandboxBuilder.buildSandbox();try {// 创建Mock对象Object mockObj = sandbox.getObject(Calculator.class.getName());when(mockObj.add(1, 2)).thenReturn(3);// 将Mock对象注册到主程序中sandbox.getApplicationClassLoader().getTransletClasses().put(Calculator.class.getName(), mockObj.getClass());// 调用Mock对象Calculator calculator = new Calculator();int result = calculator.add(1, 2);System.out.println("result: " + result);} finally {// 销毁Sandbox环境sandbox.destroy();}}static class Calculator {public int add(int a, int b) {return a + b;}}
}


http://www.ppmy.cn/news/78544.html

相关文章

《LKD3粗读笔记》(15)进程地址空间

进程地址空间:内核除了管理本身的内存外,还必须管理用户空间中进程的内存,这个内存就是进程地址空间,即系统中每个用户空间进程所看到的内存。Linux操作系统采用虚拟内存技术,系统中的所有进程之间以虚拟方式共享内存。…

arm嵌入式系统下,手把手教你移植pppoe拨号客户端,使用pppoe拨号上网

移植pppoe拨号客户端 一、概述二、移植过程1、内核配置2、pppd工具编译3、pppoe工具编译 三、配置pppoe参数四、创建节点信息五、pppoe服务器搭建 一、概述 PPPoE(英语:Point-to-Point Protocol Over Ethernet),以太网上的点对点协…

nacos+frp穿透实现局域网调用

简介:首先你要有外网服务器。在外网服务器上安装frp服务端。然后在你想要调用的局域网电脑上安装frp客户端 frp下载链接 Releases fatedier/frp GitHub 外网服务器上我用的是docker安装的。你也可以直接下载并启动。这里我就不描述了。 首先我们先创建某个目录…

全网最牛最前面的浦发银行软件测试面试题精讲分析

面试永远都是软件测试人重点关注的问题,最近也总有很多想去银行面试的小伙伴来问我,有没有什么方法技巧传授一下。 那今天就给大家总结一些浦发银行的面试题,小伙伴们可以看看如果是自己能不能流畅地回答上来这些面试题。 1、说说你们公司测…

[SHOI2008]循环的债务 题解

题目 转换问题:所有人把钱放在桌上,每个人拿走自己所需的钱。 每个人并不需要重复的把相同钞票放在桌子上再拿回来,因此对于第 i i i 种钞票,假设 Alice 初始有 x x x 张,结束有 x ′ x x′ 张,Alice 只…

量化论文学习之《基于 CNN-LSTM 混合模型的股价 预测》

主要原理 CNN-LSTM 混合模型首先使用 CNN 来提取时间序列数据的特征,然 后将特征输入进 LSTM 模型中来进行下一交易日股票收盘价的预测。 数据处理 使用数据 作者发现加入volume,pctChg后效果变差,可能原因是加入了相关性较低的特征后造成了数据冗余…

陕西棒球发展·棒球5号位

陕西省棒球发展现状: 目前,陕西省棒球运动的发展还处于初级阶段,棒球运动的普及程度和水平都相对较低。陕西省内的棒球队伍数量较少,且大多数队伍的水平较为薄弱,缺乏专业的教练和训练设施。此外,陕西省内…

为什么要学习C++软件调试技术?掌握调试技术都有哪些好处?

目录 1、为什么要学习C软件调试技术? 1.1、IDE调试手段虽必不可少,但还不够 1.2、通过查看日志和代码去排查异常崩溃问题,费时费力,很难定位问 1.3、有的问题很难复现,可能只在客户的环境才能复现 1.4、开发联调工…