前言
在之前的文章JMeter:BeanShell向JSR223迁移过程遭遇的java标准库不可用问题-如何切换JDK版本中引用了一段使用BeanShell对入参进行加密的脚本,迁移到JSR223,虽然更换JDK后编译通过,看似也可以执行了,但是其实那段脚本是有问题的。要解释这个,就要先说一下JSR223在处理groovy语言时,与BeanShell的区别。
使用groovy语言时,JSR223可先对脚本进行编译,而且,推荐缓存编译后的脚本(配置项Script compiled caching - Cache compiled script if available默认选中,且推荐保持选中状态)。这使得它在脚本的执行效率上比BeanShell+Java解释器更加高效,因而官网建议在性能测试中使用JSR223 +Groovy来替代BeanShell+Java。
但是正是由于它的编译功能和缓存编译脚本的特性,使得当在脚本中直接使用JMeter变量或JMeter内置函数时,可能会出现非预期的效果,因为它仅缓存变量的第一次替换。所以,当在JSR223中使用{key}或{function}的方式来使用属性、变量或内置函数时,它仅在第一次调用的时候对值进行更新和替换,后续将不再替换,导致这些值更新后无法获取最新值,从而出错。
示例
1、添加一个dummy sampler
在响应中,模拟返回一个json,其中res字段是一个5位的随机字符串:{res:${__RandomString(5,abcdef,)}}
2、添加json提取器,提前响应中的res字段
3、添加JSR223 PostProcessor,在res的基础上进行处理
我就是简单的,在res后面添加一个字符传:“我是飞鸟呀”,其中分别使用${key}和vars.get("key")的方式来获取res的值,以比较其不同。
String newName = "${res}_我是飞鸟呀";
vars.put("newName",newName);
String newName2 = vars.get("res") + "_我是飞鸟呀";
vars.put("newName2",newName2);
4、添加一个dummy sampler,显示第三步处理后的两个字符串
5、运行结果
单线程,执行两次,可以看到,使用{}方式获取的res,两次都是"dabdf",第二次没有按照预期更新。
而使用vars.get()方式获取的res,两次的值是不一样的,每次都拿到了最新的响应值。这才是我们实际业务中所预期的结果。
将第三步中的代码,粘贴到一个beanshell后置处理器中,再次执行,可以看到,即便是使用{}方式获取的变量,也每次都会更新:
总结
在JSR223中推荐使用vars.get(“key”)的方式使用变量,而非${key}的方式。
对于JMeter的内置函数,推荐通过Parameters passed to script来传递,在代码中通过args[]数组来调用,如下: