centos 命令行执行多个命令_命令行如何执行jar包里面的方法
最近遇到一个尴尬的问题,由于公司机测试环境的机房迁移,导致办公区的网络跟测试环境网络之前延迟比较大,大到什么程度呢?大到不能正常使用测试环境。
由于网络组一直在排查,暂时没有答复,所以只能采取一个比较临时的办法。我自己在本机用的Java
写的测试框架以及Groovy
写的测试脚本,具体情况可参考:如何统一接口测试的功能、自动化和性能测试用例。
由于本人之前拥有的一台独立物理测试机被收回,现在分给测试组的只有一个docker
容器起来的服务。本来最优的方案是在docker file
文件时候吧Groovy SDK
加上去,保证一个Groovy
运行环境,但也被否掉了,只留了一个口子给我,就是上传文件到项目Git
中,然后通过够部署项目把文件弄到docker
容器中。
Groovy SDK
又比较大,完事儿还需要重新设置环境变量等等问题,我想到了两个其他方案:
- 将项目
build
成jar
包,测试用例(也就是某个类的main
方法),通过执行jar
包中的class
类的main
方法,达到执行不同测试用例的目的,顺手做一个参数化。 - 定义一个统一的
main
方法入口,通过反射执行不同的方法。
显然第二个思路用途更广,但是实现起来略微麻烦了一些,而且传参的时候比较复杂,个人建议还是优先考虑第一种方式。
下面分享这两种方式的实现。
执行class的main方法
首先我写一个测试用例,内容如下:
package com.okayqa.composer.performance.teach1_1
import com.fun.frame.execute.Concurrentimport com.fun.frame.httpclient.ClientManageimport com.fun.frame.httpclient.FanLibraryimport com.fun.frame.thread.HeaderMarkimport com.fun.frame.thread.RequestThreadTimesimport com.fun.utils.ArgsUtilimport com.okayqa.composer.base.OkayBaseimport com.okayqa.composer.function.IMSocket
class ActivityUnread extends OkayBase{ public static void main(String[] args) { ClientManage.init(5, 5, 0, "", 0) def util = new ArgsUtil(args) def thread = util.getIntOrdefault(0, 100) def times = util.getIntOrdefault(1, 100) def base = getBase() def socket = new IMSocket(base) socket.getActivityUnread(81951375949,43519,43504) def request = FanLibrary.getLastRequest()
def mark = new HeaderMark("requestid") def times1 = new RequestThreadTimes(request, times, mark)
new Concurrent(times1, thread, "activity未读消息").start()
allOver() }}
然后使用Maven
的package
命令打包。执行Java
命令即可执行jar
包中某个class
的main
方法,可参数化。
java -cp okay_test-1.0-SNAPSHOT.jar com.okayqa.composer.performance.teach1_1.ActivityUnread 1 1 start
下面是输出:
INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/okay_test/target/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.7INFO-> requestid: Fdev1607495809625INFO-> 请求uri:https://teacherpad-stress.xk12.cn/api/t_pad/user/login,耗时:368 msINFO-> 教师:61951375269,学科:null,名称:61951375269,登录成功!INFO-> requestid: Fdev1607495810141INFO-> 请求uri:https://ailearn-composer-interface-stress.xk12.cn/api/composer/activity/course_list/unread_num,耗时:106 msINFO->~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~> {> ① . "data":{> ② . . . "activity_unread_num":[> ③ . . . . . {> ③ . . . . . "activity_id":43519,> ③ . . . . . "msg_count":208> ② . . . },> ② . . . {> ③ . . . . . "activity_id":43504,> ③ . . . . . "msg_count":0> ③ . . . . . }> ② . . . ]> ① . },> ① . "meta":{> ② . . . "emsg":"成功",> ② . . . "ecode":0> ① . }> }~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~INFO-> gc回收线程开始了!INFO-> 线程:activity未读消息0,执行次数:1,错误次数: 0,总耗时:1 sINFO-> 总计1个线程,共用时:0.059 s,执行总数:1,错误数:0,失败数:0INFO-> 数据保存成功!文件名:/Users/fv/Documents/workspace/okay_test/target/long/data/1activity未读消息20201209143650INFO->~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~> {> ① . "rt":56,> ① . "total":1,> ① . "qps":17.857142857142858,> ① . "failRate":0.0,> ① . "threads":1,> ① . "startTime":"2020-12-09 14:36:50",> ① . "endTime":"2020-12-09 14:36:50",> ① . "errorRate":0.0,> ① . "executeTotal":1,> ① . "mark":"activity未读消息20201209143650",> ① . "table":""> }~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~INFO->INFO-> gc回收线程结束了!
完美执行1 !!!
反射执行方法
首先封装一个反射执行的工具类,代码如下:
package com.fun.frame.execute;
import com.alibaba.fastjson.JSON;import com.fun.base.exception.FailException;import com.fun.config.Constant;import com.fun.frame.SourceCode;import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;import org.slf4j.Logger;import org.slf4j.LoggerFactory;
import java.io.File;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.net.URL;import java.util.ArrayList;import java.util.Arrays;import java.util.List;
@SuppressFBWarnings({"NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", "NP_NULL_ON_SOME_PATH_EXCEPTION"})public class ExecuteSource extends SourceCode {
private static Logger logger = LoggerFactory.getLogger(ExecuteSource.class);
/** * 执行包内所有类的非 main 方法 * * @param packageName */ public static void executeAllMethodInPackage(String packageName) { List classNames = getClassName(packageName);if (classNames != null) {for (String className : classNames) { String path = packageName + "." + className; executeAllMethod(path);// 执行所有方法 } } }/** * 执行一个类的方法内所有的方法,非 main,执行带参方法的代码过滤 * * @param path 类名 */public static void executeAllMethod(String path) { Class> c = null; Object object = null;try { c = Class.forName(path); object = c.newInstance(); } catch (Exception e) { e.printStackTrace(); } Method[] methods = c.getDeclaredMethods();for (Method method : methods) {try { method.invoke(object); } catch (IllegalAccessException e) { logger.warn("非法访问导致反射方法执行失败!", e); } catch (InvocationTargetException e) { logger.warn("反射调用目标异常导致方法执行失败!", e); } catch (Exception e) { logger.warn("反射方法执行失败!", e); } finally { sleep(Constant.EXECUTE_GAP_TIME); } } }/** * 提供给命令行main方法使用 * * @param params */public static void executeMethod(String... params) { String[] ps = Arrays.copyOfRange(params, 1, params.length); executeMethod(params[0], ps); }/** * 执行具体的某一个方法,提供内部方法调用 * * @param path */public static void executeMethod(String path, Object... paramsTpey) {int length = paramsTpey.length;if (length % 2 == 1) FailException.fail("参数个数错误,应该是偶数"); String className = path.substring(0, path.lastIndexOf(".")); String methodname = path.substring(className.length() + 1); Class> c = null; Object object = null;try { c = Class.forName(className); object = c.newInstance(); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { logger.warn("创建实例对象时错误:{}", className, e); } Method[] methods = c.getDeclaredMethods();for (Method method : methods) {if (!method.getName().equalsIgnoreCase(methodname)) continue;try { Class[] classs = new Class[length / 2];for (int i = 0; i 2) { classs[i / 2] = Class.forName(paramsTpey[i].toString());//此处基础数据类型的参数会导致报错,但不影响下面的调用 } method = c.getMethod(method.getName(), classs); } catch (NoSuchMethodException | ClassNotFoundException e) { logger.warn("方法属性处理错误!", e); }try { Object[] ps = new Object[length / 2];for (int i = 1; i 2) { String name = paramsTpey[i - 1].toString(); String param = paramsTpey[i].toString(); Object p = param;if (name.contains("Integer")) { p = new Integer(changeStringToInt(param)); } else if (name.contains("JSON")) { p = JSON.parseObject(param); } ps[i / 2] = p; } method.invoke(object, ps); } catch (IllegalAccessException | InvocationTargetException e) { logger.warn("反射执行方法失败:{}", path, e); }break; } }/** * 获取当前类的所有用例方法名 * * @param path * @return */public static List getAllMethodName(String path) { List methods = new ArrayList<>(); Class> c = null; Object object = null;try { c = Class.forName(path); object = c.newInstance(); } catch (Exception e) { FailException.fail("初始化对象失败:" + path); } Method[] all = c.getDeclaredMethods();for (int i = 0; i String str = all[i].getName(); methods.add(str); }return methods; }/** * 获取某包下所有类 * * @param packageName 包名 * @return 类的完整名称 */public static List getClassName(String packageName) { List fileNames = new ArrayList<>(); ClassLoader loader = Thread.currentThread().getContextClassLoader();// 获取当前位置 String packagePath = packageName.replace(".", Constant.OR);// 转化路径,Linux 系统 URL url = loader.getResource(packagePath);// 具体路径if (url == null || !"file".equals(url.getProtocol())) { FailException.fail("获取包路径失败!"); } File file = new File(url.getPath()); File[] childFiles = file.listFiles();for (File childFile : childFiles) { String path = childFile.getPath();if (path.endsWith(".class")) { path = path.substring(path.lastIndexOf(OR) + 1, path.lastIndexOf(".")); fileNames.add(path); } }return fileNames; }}
使用Demo
如下:
package com.fun.main;
import com.fun.frame.SourceCode;import com.fun.frame.execute.ExecuteSource;
public class ExecuteMethod extends SourceCode {
public static void main(String[] args) { args = new String[]{"com.fun.ztest.java.T.test", "java.lang.Integer", "1"}; ExecuteSource.executeMethod(args); }
}
其中T
的代码中test()
方法如下:
public static void test(int i) { output(33333333 + i); }
这里我模拟了args
参数,可以看出这里的参数非常复杂,都是较长的String
字符串。
控制台输出:
INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.7WARN-> 方法属性处理错误!java.lang.NoSuchMethodException: com.fun.ztest.java.T.test(java.lang.Integer) at java.lang.Class.getMethod(Class.java:1786) ~[?:1.8.0_51] at com.fun.frame.execute.ExecuteSource.executeMethod(ExecuteSource.java:106) [classes/:?] at com.fun.frame.execute.ExecuteSource.executeMethod(ExecuteSource.java:77) [classes/:?] at com.fun.main.ExecuteMethod.main(ExecuteMethod.java:10) [classes/:?]INFO-> 33333334
Process finished with exit code 0
- 这里的报错是因为
test()
方法的参数是int
并不是我传入的java.lang.Integer
导致的,单并不影响后面的方法调用正常执行,可忽略。
完美执行2 !!!
- 还有一种神器可以解决这个问题:arthas,可以通过arthas命令redefine实现Java热更新的方式替换方法类,这个比较复杂,而且适用范围更窄,不可取。
公众号FunTester,非著名测试开发,文章记录学习和感悟,欢迎关注,交流成长。
FunTester热文精选
- 如何成为全栈自动化工程师
- 绑定手机号性能测试
- 固定QPS压测初试
- 开源礼节
- Groovy在JMeter中应用专题
- 基于WebSocket的client封装
- 基于Socket.IO的Client封装
- Socket.IO接口多用户测试实践
- 好书推荐《Java性能权威指南》
- 所谓UI测试
centos 命令行执行多个命令_命令行如何执行jar包里面的方法相关推荐
- Jar包冲突解决方法 Unknown lifecycle phase mvn Eclipse中执行maven命令
1.如下图,右击需要执行maven命令的工程,选择"Debug As"或"Run As",再选择"Maven build..." 进行如上操 ...
- java打包拆包_[Java] Java 打包成jar包 和 解压jar包
解压jar包 jar xf xxx.jar 打包成jar包 方法一:通过jar命令 jar命令的用法: 下面是jar命令的帮助说明: 用法:jar {ctxui}[vfm0Me] [jar-file] ...
- jar包 jdk 停_一文读懂jar包的小秘密
简介 java程序员每天不是在创建jar包就是在创建jar包的路上,并且各种依赖引用都是以jar包的形式展示的.但是随着现代IDE的出现,我想很多程序员已经基本上很少直接和jar包打交道了. 换句话说 ...
- 常用jar包_几个解决 Maven Jar 包冲突的小技巧.
前言 大家在项目中肯定有碰到过Maven的Jar包冲突问题,经常出现的场景为: 本地运行报NoSuchMethodError,ClassNotFoundException.明明在依赖里有这个Jar包啊 ...
- java jar在后台运行_【Java】部署jar包并后台运行
Linux环境部署: 1.执行jar包的命令和在windows操作系统上是一样 java -jar jarName-0.0.1-SNAPSHOT.jar; 注: 关闭服务器连接时会关闭此程序进程,(推 ...
- mac 命令行 解压7z文件_命令行压缩解压缩一 7z
命令行压缩解压缩一 7z 1) 简介 7z,全称7-Zip, 是一款开源软件.是目前公认的压缩比例最大的压缩解压缩软件. 主页:http://www.7-zip.org/ 中文主页:http://7z ...
- mac 命令行 解压7z文件_命令行压缩解压7z
命令行压缩解压一 7z 1) 简介7z,全称7-Zip, 是一款开源软件.是目前公认的压缩比例最大的压缩解压软件.主页:http://www.7-zip.org/中文主页:http://7z.spar ...
- 命令行curl上传文件_命令行基础知识:使用cURL下载文件
命令行curl上传文件 Client URL, or simple cURL is a library and command-line utility for transferring data b ...
- scala学习-Linux命令行运行jar包传入main方法参数
1.eclipse写了一个程序,直接打包成jav普通jar包,然后无法选择主类,但是运行的时候,可以指定参数,(参数在程序里用 args(i)引用,注意是括号) 2.运行的时候,参数跟在jar包后面, ...
最新文章
- 解读模拟摇杆原理及实验
- [云炬创业基础笔记]第二章创业者测试17
- mysql emoji表情_让MySQL支持Emoji表情 mysql 5.6
- 损失函数与优化器理解+【PyTorch】在反向传播前为什么要手动将梯度清零?optimizer.zero_grad()
- 对象输出流 ObjectOutputStream java
- 【福利】计算机公开课合集(视频教程)
- OpenShift 4.6 新特性 - 用 Windows MachineConfig Operator 管理 Windows Container
- 卷积神经网络——第一周 卷积神经网络基础——第二部分
- Java程序员必备!Dagger2源码分析(二(1)
- Pwn2Own 2020线上争霸赛落幕:Fluoroacetate 团队四度蝉联 Master of Pwn!
- Zabbix---5 监控linux服务器目录大小
- 苹果mac好用的记事本软件:Ulysses 24
- redis 加载mysql_Mysql Redis PostgreSQL数据库查看客户端连接
- 「无捆绑不锁页」极度纯净win10 32位专业版下载地址
- 1.0 信息化与信息系统
- python如何输入整数求和_Python如何输入数字并求和
- 【愚公系列】2022年10月 微信小程序-电商项目-商品详情页面说明和商品导航
- (附源码)springboot宠物管理系统 毕业设计 121654
- HDOJ 4622 Reincarnation (hash)
- video标签设置autoplay(自动播放)无效
热门文章
- STM32工作笔记0052---串口通信原理--UART
- SpringCloud工作笔记052---各种数据库在java中的连接配置_以及连接驱动
- SpringCloud学习笔记014---可以使用json对rabbitmq进行封装,方便数据传输
- 解决Fail to create the java Virtual Machine
- 学习使用c++编写opencv的一些记录
- typescript parseint不能传number_Typescript 使用日志
- verilog学习记(加法器)
- 51单片机几种精确延时(包含自动适应主时钟)
- 成功没有捷径python_成功,大部分时候并没有捷径
- 使用函数求余弦函数的近似值_WPS-Excel表格实用技巧-排名函数RANK函数的使用