关于beanshell中日期比较大小的信息
beanshell和shell的区别
BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法;
BeanShell是一种松散类型的脚本语言(这点和JS类似)
BeanShell是用Java写成的,一个小型的、免费的、可以下载的、嵌入式的Java源代码解释器,
具有对象脚本语言特性,非常精简的解释器jar文件大小为175k。
BeanShell执行标准Java语句和表达式,另外包括一些脚本命令和语法。
官网:
BeanShell 将成为Java平台上的第三种编程语言,前两种分别为java和Groovy(也是一种脚本语言)
下载与安装:
jar:
src:
或使用SVN:
svn co
doc:
设置环境:
(1) 把bsh-xx.jar放到$JAVA_HOME/jre/lib/ext文件夹下(不推荐);
(2) UNIX: export CLASSPATH=$CLASSPATH:bsh-xx.jar(推荐)
(3) WINDOWS: set classpath %classpath%;bsh-xx.jar(推荐)
运行方式:
(1) 界面UI方式 : java bsh.Console
(2) 命令行方式 : java bsh.Interpreter
(3) 运行脚本文件: java bsh.Interpreter filename [args]
简单举例(windows):
设置好环境变量classpath, 打开dos或CMD窗口, 键入命令:
java bsh.Console
出现BeanShell的"Bsh Workspace"界面,表示设置成功,BeanShell开始运行;
在使用上面命令出现的控制台界面中进行下面的测试:
bsh % foo="Foo"; //定义变量foo
bsh % four=(2+2)*2/2; //定义变量four并初始化为(2+2)*2/2
bsh % print(foo+"="+four); //输出 Foo=4
Foo=4 //输出结果
bsh % for(i=0;i5;i++)print(i); //循环打印0~4
1
2
3
4
bsh % button = new JButton("MyButton"); //实例化一个Button对象
bsh % frame = new JFrame("MyFrame"); //实例化一个Frame对象
bsh % frame.getContentPane().add(button,"Center"); //将Button对象加入Frame对象的面板中;
bsh % frame.pack(); //打包
bsh % frame.setVisible(true); //设置Frame对象的可见性;回车后会弹出一个GUI界面;
bsh %
完整代码:
foo = "Foo";
four = (2 + 2)*2/2;
print( foo + " = " + four );
for (i=0; i5; i++)
print(i);
button = new JButton( "My Button" );
frame = new JFrame( "My Frame" );
frame.getContentPane().add( button, "Center" );
frame.pack();
frame.setVisible(true);
在窗口中输入上面的代码, 敲回车执行,弹出一个有Button的GUI界面.
说明:
因为BeanShell是松散类型的脚本语言因此可以直接写:
foo = "Foo";
four = (2 + 2)*2/2;
也就是foo与four均不需要变量类型的声明,给赋什么类型的值,就是什么类型的变量;
print()是BeanShell提供一种简单的打印命令,相当于java中的System.out.println();
脚本中所写的方法范例:
int addTwoNumbers( int a, int b ) {
return a + b;
}
sum = addTwoNumbers( 5, 7 ); // 12
也可以使用动态的变量类型(无状态)方法
add(a, b){
return a + b;
}
foo = add(1, 2); // 3
foo = add(1, "2"); //"12"
特别注意:
只要有一个为字符串全部按照字符串处理,
系统不会根据1是数字在前把"2"转换成数字处理;
foo = add("Oh", " baby"); // "Oh baby"
脚本中实现接口:
实现任何接口需要JDK1.3或者更高,可以使用缺省的java匿名类的语法实现一个接口类,例如:
ActionListener scriptedListener = new ActionListener() {
actionPerformed( event ) { ... }
}
不需要实现接口的所有的方法,只需要实现你使用的方法即可, 如果使用你没有实现的方法,
BeanShell将抛出一个错误,如:
ml = new MouseListener() {
mousePressed( event ) { print("test"); }
// handle the rest
invoke( name, args ) {
print("Method: "+name+" invoked!");
}
}
脚本中定义对象:
例一:
使用特殊的关键字this可以创建一个对象(根JS类似)
foo() {
print("foo");
x=5;
bar() {
print("bar");
}
return this;
}
myfoo = foo(); // prints "foo"
print( myfoo.x ); // prints "5"
myfoo.bar(); // prints "bar"
例二:
在java标准语言中可以使用this返回一个类的一个实例
// MyClass.java
MyClass {
Object getObject() {
return this; // return a reference to our object
}
}
在这个例子中getObject() 方法是返回MyClass类的一个实例
在BeanShell中对象中的变量只是局部的变量在对象内可以使用,
在对象外是不可以使用的(不同于前面for-loop,if-else中的使用);
// Define the foo() method:
foo() {
bar = 42;
print( bar );
}
// Invoke the foo() method:
foo(); // prints 42
print(bar); // Error, bar is undefined here
这里的print(bar);会抛出异常:
// Error: EvalError: Undefined argument: bar : at Line: 1 : in file: unknown file : ( bar )
但可以使用this返回对象,使用对象加上"."运算符引用属性(类似JS)
foo() {
bar = 42;
return this;
}
fooObj = foo();
print( fooObj.bar ); // prints 42
同样对象中也可以定义一些方法,例如:
foo() {
int a = 42;
bar() {
print("The bar is open!");
}
//bar();
return this;
}
// Construct the foo object
fooObj = foo(); // prints "the bar is open!"
// Print a variable of the foo object
print ( fooObj.a ) // 42
// Invoke a method on the foo object
fooObj.bar(); // prints "the bar is open!"
也可以定义bar()和foo()也带参数:
foo() {
bar(int a) {
print("The bar is open!" + a);
}
return this;
}
foo().bar(1);
也可以把bar()方法定义到对象外面
foo() {
return this;
}
bar(int a) {
print("The bar is open!" + a);
}
foo().bar(1); //其实就是bar(1);
BeanShell一种松散的脚本语言, 有很多中声明的方法可以使用:
This super global
This 是引用当前对象
Super 是引用父亲对象
Global 是引用最上层对象
super.super.super...foo = 42; // Chain super. to reach the top
global.foo = 42;
BeanShell(Bsh)调用外部Java类的两种方式:
(1) 方法一(直接调用.java源文件)
sourceRelative("xxx.java");
利用sourceRelative()方法把java的源代码引入bsh环境中,然后进行调用。
这种方法不需要编译引用的java源文件,缺点也很明显"无法利用javac来检查java代码"。
(2) 方法二(通过引用.class二进制文件)
import xxx;
利用传统的java import机制来获取java类,然后在bsh环境中进行调用。
需要编译.java文件;
方便调用第三方的Java API(因为通常情况下无法得到API的源码,即使得到了文件会远大于jar包的大小)。
BeanShell介绍:
我们知道,现在有很多脚本语言,大家平时使用的比较多的包括Perl,Python,Ruby,JavaScript,Groovy,
在这里我要介绍的是另外一个对象脚本语言BeanShell()。
BeanShell的解释器是用Java写的,开源并且免费的,
引用open-open上面的话来说明它的运作方式:
它将脚本化对象看作简单闭包方法(simple method closure)来支持,
就如同在Perl和JavaScript中的一样。它具有以下的一些特点:
* 使用Java反射API以提供Java语句和表达式的实时解释执行;
* 可以透明地访问任何Java对象和API;
* 可以在命令行模式、控制台模式、小程序模式和远程线程服务器模式等四种模式下面运行;
* 与在应用程序中一样,可以在小程序中(Applet)正常运行(无需编译器或者类装载器);
* 非常精简的解释器, jar文件中的Intepreter.class大小为150+k"。
每一种脚本语言都有它的使用场景,而正是因为其在某些场景的使用而使语言本身得到了发扬光大,
比如Ruby正是因为Ruby On Rails这个Web框架的流行而得到开发者的关注,Groovy也一样;
BeanShell可不能再有Web框架,Java世界的Web框架已经太多了,够让人头痛的了;
BeanShell是Java语法,所以对Java开发者来说,很快就可以上手,
BeanShell不能像Ruby,Perl,Ruby一样可以占据一个系统的主体,
而只能在一些小的地方发挥"螺丝钉"的作用。
笔者与BeanShell结缘是通过一个开源工作流引擎-OBE(这个鸟东西现在好像没什么声音了),
BeanShell被用作流程跳转的Parser,举个例子,比如一个流程A节点的下一个节点是B或者C,
如何决定A-B还是A-C呢,我们可以写一段Java脚本放在流程定义里面,
一旦A运行完毕,流程会使用BeanShell来Parse这段Java脚本,
根据脚本的返回值决定流程下一步的运行方向,
脚本在这里虽然用得不多,但是却是非常的重要,
我们知道,简单的表达式是远远满足不了流程跳转的判断的,
有了脚本就可以满足任何不规则的业务逻辑。
继以上说到的,使用BeanShell可以处理现实中不规则的业务,举个很典型的例子,
我们知道,一个保险公司有很多险种,每个险种的投入和收益的算法是很复杂的,
无法用规则的关系数据库模型来描述,所以很多保险系统在处理险种的算法都是硬编码,
如果要在系统中新加一个险种,是非常麻烦的,重新修改代码,重新发布,
这对开发\维护人员和客户都是很痛苦的,有了BeanShell,我们可以从这种痛苦中解脱出来,
对每个险种使用不同的脚本,新加的险种我们新配一个脚本,这样既可以满足业务多变的要求,
又可以减少工作量,节约成本。
BeanShell的一个特点是动态执行Java代码,脚本文件改变不会影响当前脚本的调用,
新脚本将在脚本的下一次调用生效,这不同于配置文件,配置文件改变一般都需要应用重启。
下面举个例子来说明BeanShell的使用(JDK1.5,BeanShell2.04),
主类:
package com.test.BeanShell;
import bsh.Interpreter;
public class TestShell {
public static void main(String[] args) throws Exception {
Interpreter interpreter = new Interpreter();
interpreter.set("inValue", new Integer(1));
interpreter.source("/D://BeanShell_test/test.bsh");
System.out.println(((Integer) interpreter.get("outValue")).intValue());
}
}
脚本文件(D:/BeanShell_test/test.bsh)中的内容为::
System.out.println("hello,in value is "+inValue);
outValue = inValue+1;
结果:
hello,in value is 1
2
再来一个简单例子:
(1) 下载BeanShell的jar,加到 classpath 里
(2) 写一个脚本文件 myscript.txt ,内容如下:
a = 2;
b = 3;
c = a + b;
print(c);
(3) 运行该脚本
d:\BeanShelljava bsh.Interpreter myscript.txt
如果没有将BeanShell的JAR加到classpath路径里,运行下面的命令:
java -classpath %CLASSPATH%;bsh-2.0b4.jar bsh.Interpreter myscript.txt
OK,输出结果5
写一个bat文件 bsh.bat放到系统目录下,如:winnt 文件内容如下:
java bsh.Interpreter %1
就可以使用如下方法运行脚本文件了
c:\BeanShellbsh myscript.txt
osworkflow用的就是他了
和Eclipse的集成:
eclipse update url:
有用的BeanShell命令:
在刚才那个例子中我们用了一个内建在BeanShell中的一个方便的命令print(),来显示变量的值。
print()跟Java的System.out.println()非常的相像,除非它能保证输出总是命令行。
print()也可以显示一些对象的类型(如数组),但比Java的更详细。
另一个相关的命令是show(),用来开启与关闭显示你输入的每一行的结果。
jmeter beanshell中设置sleep会影响响应时间吗
jmeter beanshell中设置sleep会影响响应时间
一、操作变量:通过使用Bean shell内置对象vars可以对变量进行存取操作
a) vars.get("name"):从jmeter中获得变量值
b) vars.put("key","value"):数据存到jmeter变量中
二、操作属性:通过使用Bean shell内置对象props 可以对属性进行存取操作
a) props.get("START.HMS");注:START.HMS为属性名,在文件jmeter.properties中定义
b) props.put("PROP1","1234");
三、自定义函数:
在BeanShell中,我们可以使用java语言自定义函数来处理特定的逻辑,结合BeanShell的内置对象进行变量的存取,方便我们进行测试提高脚本的灵活性。
JMeter测试配置优化指南
经常有客户问XMeter君,就是单个JMeter能最大支持多少虚拟用户?这个问题其实很难给出一个很准确的答案。因为虚拟用户本身是一个抽象的概念,每个虚拟用户可以是模拟不同的协议。就像如果别人问某个容器能装多少东西这种问题,因为东西本身不确定的话,你也无法给出一个确定的答案。当然了,容器大小本身是确定的,我们只能说在给定的容器的范围内,是否有一些方式来优化,能够让一个容器装下更多的一个确定的东西。毕竟有的时候如果把所有潜能发挥出来,还是很可观的呢。那言归正传,XMeter君带大家来看看JMeter有哪些地方可以优化。
限制JMeter上模拟的虚拟用户的瓶颈主要有计算资源(CPU),存储(内存)和操作系统资源的限制等,下面分开讲述。
计算资源主要指的就是CPU,不同的测试脚本对CPU的使用可能会有很大的差别。在编写、执行测试脚本的时候可以考虑下面的一些问题。
1)JMeter脚本在运行过程中应该避免循环执行大量计算的工作:比如测试脚本中每个虚拟用户循环使用了BeanShell对数据进行处理,如果真的有此需求的话,建议使用扩展function。读者可以参考XMeter君写的 这篇文章 来比较BeanShell和原生function的处理效率。或者准备数据的部分是不是只需要执行一次?比如将这部分逻辑放在“只执行一次”控制器里。
2)JMeter在UI模式下运行也会消耗更多的CPU资源,建议脚本调试通过之后,实际运行测试的时候通过在命令行下来运行测试脚本
3)JMeter的各种图形化的监听器也会消耗CPU资源,在实际的测试运行过程中可以把这些不必要的监听器都关闭,只保留必要的监听器
在自己实现插件的时候,需要考虑实现比较高效的一些算法,如果一个比较差的算法导致耗费额外的CPU,上千个线程累计起来是非常可观的,所以在插件实现一些偏计算的方面模拟的时候,一定要做到精打细算。
存储主要指的就是内存。JMeter是由Java实现的,而Java应用吃内存大家都觉得是很正常,但是这部分是否有优化的空间呢?答案是肯定的。JMeter和普通的Java应用程序一样,启动后使用的内存主要包括两个部分栈和堆。
1)栈空间主要用于分配在方法调用过程中压入栈的方法调用的参数值等。栈空间的使用是和线程数目基本上成正比的,Java 8中缺省每个线程会分配1MB的栈空间。如果使用的是32位的系统,由于一个进程的寻址空间为4GB,假设系统还需要留1GB的内存空间,那么就算把所有的内存都分配给栈,最多也就是能创建3000个线程。当然,如果是使用了64位的系统的话,基本上就没有这个限制了(实际上还受限于操作系统的一些软配置,本文稍后会提及)。假如你的测试脚本(实际上取决于插件的实现)并没有递归等复杂的栈调用,那么可以把每个线程所需的栈空间调小。调每线程栈空间的使用可以通过打开jmeter.sh/jmeter.bat,通过加入下面的语句来解决,例子中的配置的意思是每线程使用400KB的栈空间,比缺省的1MB节省了约60%,对于需要创建大量的线程的JMeter来说,节省的空间还是比较可观的。但是实际上在运行过程中,栈空间的使用也不完全是线性的,JVM或者操作系统可能在某些地方还是共享了一些栈空间,具体的节省下来的栈空间需要通过试验才能得到准确的数值。
2)堆则包括分配对象实例所需要的静态变量、类变量等。这部分所用的内存取决于插件的实现,比如每个Sampler所依赖的对象的大小等。这部分空间的调整可以通过设置Xmx参数来实现。做法还是通过打开jmeter.sh/jmeter.bat,下面的例子的意思是上来就在堆空间上分配15GB内存,最大可以使用的堆的空间的大小也是15GB。
在自己实现JMeter插件的时候应该仔细考虑以上的问题,比如避免在Sampler中再单独启动线程,因为这么做会使每个虚拟用户创建额外的一个线程,从而可能导致在同样的配置下,你实现的插件创建少一半的虚拟用户!比较好的做法是所有虚拟用户通过一个线程来处理,不过这样也会导致多线程之间数据使用的冲突等问题,读者需要根据自己的情况酌情处理。针对堆空间的使用,如果有比较占存储空间的类变量,可能尽量多线程共享一份数据(比如通过静态变量等),而不是每线程创建自己的实例,当然还是需要考虑多线程访问的时候变量保护的问题。
操作系统的缺省配置可以满足大部分用户的日常使用,而性能测试往往会突破这些操作系统默认的配置。常见的包括文件、端口限制等。本文以CentOS为例,介绍如何优化这些配置。
1)设定每个进程可以打开的最大文件描述符的数量,由于在Linux中一个socket连接也是文件描述符,而性能测试过程过程中往往测试的时候也需要生成一个socket连接,因此该参数的设置会影响到最大模拟的虚拟用户数。
2)设置系统可用的socket端口号,每台机器最多可用的端口号为65535,在测试机器上可能某些系统的端口已经被占用,因此用户可以设置可用的端口号段来增加可用的端口。如下例所示可用的端口号为15000至61000,那么最多的可用端口号数目为46000个。如果需要设置Docker容器中的该配置,需要在特权模式下才能对其进行配置,否则该项配置是只读的(docker run --privileged)
3)tcp_tw_reuse表示可以复用处于TIME_WAIT状态的连接,对于在性能测试过程中可能产生的大量临时的短连接,该选项可以重用连接,而不用等待连接的完全释放,从而能提高支持的并发用户数目。tcp_tw_recycle用于回收处于TIME_WAIT状态的连接,也可以提高连接的使用率。
4)提高线程的使用限制。pid_max用于控制操作系统线程ID的最大值,该值会影响可以创建的最大的线程数目。max_map_count单进程mmap的限制会影响当个进程可创建的线程数,需要将该值也提高以支持创建更多的线程。
通过上文的介绍,读者可以对JMeter运行环境做一些比较常见的优化。针对不同的测试,读者还是需要分析不同的场景,针对压力发起机的实际情况分别进行优化,以提高单台机器上模拟的并发用户数目。如果使用XMeter平台,我们对压力机已经进行了配置优化,避免测试人员纠结于类似的底层系统的配置,只需将精力放在测试业务逻辑的编写和调试,执行的事情交给XMeter平台就可以了,因此能极大地提高测试的工作效率。
什么限制了创建Java线程的数量 :本文中介绍了更改栈大小的配置对生成的线程个数的影响
Java栈大小的设置 :与上文类似,介绍如何设置Java的栈大小
Linux中能创建的最大线程个数 : 本回答介绍的在Linux中对创建线程个数影响的一些配置
jmeter中的beanshell里怎么判断两个值大小
加入“后置处理器”-“正则表达式提取器”:引用名称即使用的参数名;填入正则表达式;模板选取匹配的组;匹配数字为匹配的个数,负数表示全部匹配;缺省值为没有匹配到时的取值。示例中用正则表达式匹配出产品id作为后续使用的参数。提取到的参数,调用时用${product_id_1},${product_id_2},${product_id_3}……;如果想要得到匹配出的参数的个数,用${product_id_matchnr};如果想随机选取其中一个,只需将匹配数字设为0,使用${product_id}调用即可。可以一次匹配多组;示例中只匹配了一个,假如正则表达式为name="chkproductids"
id="chk(.+?)"
value="(.+?)",就会有两组参数;想获得匹配到的组个数用${product_id_g};模板针对的是匹配到的字符串再做组的区分,比如希望${product_id}取出的是第二组参数的值,用$2$。
jmeter中实现每隔一定时间登陆
? ? ?? 在实际项目的测试中,往往会遇到业务流程必须是先登录再执行后续相关操作的业务场景。有的登录请求中会用到token的验证,token的实效时长设定的比较短,项目组又不愿意去修改实效时长。此时在测试稳定性的过程中必须在token实效前重新进行一次登录操作。
? ? ? ? 目前使用jmeter的测试过程中未想到其他的好方法,暂时的实现方法如下:
登录操作放到仅一次控制器中,在仅一次控制器中使用beanshell脚本获取当前的时间,仅一次控制器后面增加beanshell脚本判断运行时长,脚本后面增加if控制器判断运行时长,若超过条件则重新进行登录操作,并在if控制器下增加beanshell再次获取当前时间戳。
? ? ? ? 具体jmeter脚本实现如下:
1、脚本结构
2、仅一次控制器中beanshell sampler获取当前时间内容:
long timestart = System.currentTimeMillis()/1000;
String timestartString = String.valueOf(timestart);
vars.put("timestartString",timestartString);
3、Beanshell 判断运行时长脚本内容:
long timesNow = System.currentTimeMillis()/1000;
String aaa = vars.get("timestartString");
long timestartLong = Long.parseLong(aaa);
long bbb = timesNow-timestartLong;
vars.put("bbb",String.valueOf(bbb));
//log.info("生成数值测试cccccccccc"+bbb);
4、if逻辑控制器中内容:jexl3函数的使用可自行查找。
5、if控制器下的beanshell sampler再次获取时间戳内容:
long timestart = System.currentTimeMillis()/1000;
String timestartString = String.valueOf(timestart);
vars.put("timestartString",timestartString);
//log.info("生成数值测试cccccccccc");
? ? ? ? 以上是针对登录token实效后重新刷新或者登录的实现方法的记录,后续获取其他同学有更好的方法可分享学习。