在做dubbo的jmeter压测时,需要把jar包放入jmeter的lib/ext目录下,但是jmeter启动的时候会自动加载这个目录lib目录及lib/ext目录,这样启动后放入这些目录下的jar包就不会加载了。
jmeter的master--slave/client模式下,作为jmeter client,jmeter-server服务一直是启动的,当新的jar包放入client后,无法读取,因此需要client的jmeter动态加载这些新放入的jar包。
解决办法参考:http://blog.csdn.net/kekadm/article/details/51783240
继上篇文章《Jmeter+H2Database动态部署JAR包到代理端》实现了测试业务jar包的动态部署后,再不重启代理端Jmeter的情况下,jar的变化内容仍无法自动加载到Jmeter内存,所以还是不能实现一次启动,动态更新的目的。
因为,Jmeter在启动的时候会自动加载lib目录下的jar包,如果不重启,目录下更新的jar包也不能加载到内存。所以,要实现类的动态加载,必须在Jmeter测试类中实现业务类的重载。
即在Jmeter测试类中的setupTest()方法中要自定义代码实现业务类的加载。
此处以一个简单例子说明实现过程:
编写要被测业务类:TransDemo.java
package perftest.jmeter.trans;
public class TransDemo {
public String action(){
Stringstr = "action1st.";
System.out.println(str);
return str;
}
public voidinit() {
System.out.println("testingstart....");
}
public voidend() {
System.out.println("testingover!!!!");
}
}
将其导出为perftest-trans.jar,将这个包放到jmeter/lib目录以外的地方。如:c:/perftest-trans.jar (不能放在Jmeter/lib目录下)。
编写Jmeter测试类:TransDemoActions.java
package perftest.jemter.action;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;
public classTransDemoActions extends AbstractJavaSamplerClient{
SampleResultresult= null;
public Class<?>trans = null;
Arguments params= null;
Method methodInit= null;
Method methodAction= null;
Method methodEnd= null;
MyClassLoader classLoader= null;
Object newTrans= null;
/**
* 自定义类加载方法
* @param jarpath
* @param classpath
*/
public void loadClass(String[] jarpath,Stringclasspath){
URL[] urls= new URL[] {};
classLoader = new MyClassLoader(urls,null);
try {
for(String jar:jarpath){
classLoader.addJar(new File(jar.trim()).toURI().toURL());
System.out.println("load jar file : "+jar.trim());
}
trans = classLoader.loadClass(classpath);
System.out.println("load class file : "+classpath);
methodInit = trans.getDeclaredMethod("init");
methodAction = trans.getDeclaredMethod("action");
methodEnd = trans.getDeclaredMethod("end");
boolean accessible = methodInit.isAccessible();
if(accessible ==false){
methodInit.setAccessible(true);
}
newTrans = trans.newInstance();
} catch (Exceptione) {
e.printStackTrace();
}
}
/**
* 自定义jmeter外部参数
*/
public Arguments getDefaultParameters() {
Arguments params= new Arguments();
params.addArgument("TRANS_JARPATH","c:/perftest-trans.jar");
params.addArgument("TRANS_CLASSPATH","perftest.jmeter.trans.TransDemo");
returnparams;
}
public void setupTest(JavaSamplerContext arg0) {
try {
loadClass(arg0.getParameter("TRANS_JARPATH").split(","),arg0.getParameter("TRANS_CLASSPATH"));
//通过反射调用TestDemo的init()方法,下同
methodInit.invoke(newTrans);
}catch(IllegalAccessException e) {
e.printStackTrace();
}catch(IllegalArgumentException e) {
e.printStackTrace();
}catch(InvocationTargetException e) {
e.printStackTrace();
}
}
@Override
public SampleResult runTest(JavaSamplerContextarg0) {
try {
methodAction.invoke(newTrans);
}catch(IllegalAccessException e) {
e.printStackTrace();
}catch(IllegalArgumentException e) {
e.printStackTrace();
}catch(InvocationTargetException e) {
e.printStackTrace();
}
returnresult;
}
public void teardownTest(JavaSamplerContext arg0) {
try {
methodEnd.invoke(newTrans);
}catch(IllegalAccessException e) {
e.printStackTrace();
}catch(IllegalArgumentException e) {
e.printStackTrace();
}catch(InvocationTargetException e) {
e.printStackTrace();
}catch (Exceptione) {
e.printStackTrace();
}
}
/**
* 自定义内部类实现动态加载class
* @author
*
*/
static class MyClassLoader extends URLClassLoader {
public MyClassLoader(URL[]urls) {
super(urls);
}
public MyClassLoader(URL[]urls, ClassLoader parent) {
super(urls,parent);
}
public void addJar(URL url) {
this.addURL(url);
}
}
}
将其导出为perftest-actons.jar,并将它放入<jmeterPath>/lib/ext下,在Jmeter启动时可以自动发现这个测试类: perftest.jemter.action.TestDemoActons 。
启动Jmeter,建立测试计划和添加线程组及“Java请求”
线程组大小设置为1,线程循环次数设置2:即一个虚拟用户进行2次迭代。
运行测试
运行测试可以看到System.out.println的输出结果:
修改被测业务类TransDemo的action()方法
public String action(){
//此处修改打印输出字符
String str = "actionsecond.";
System.out.println(str);
return str;
}
重新将TransDemo.class打包为perftest-trans.jar,并覆盖前面的c:/perftest-trans.jar
重新运行测试
在不关闭和重启Jmeter的情况下,再次执行测试,可以看到输出信息已经改变为“action seconde.”:
小结:
所以要实现类的动态加载,必须在Jmeter测试类AbstractJavaSamplerClient(java请求)中使用URLClassLoader实现被测业务类的重新加载,并使用invoke()方法调用业务方法。
自此,通过《Jmeter+H2Database动态部署JAR包到代理端》及本篇可以为分布式测试中的众多代理端实现被测业务(jar)包的实时更新及业务测试类(class)的热加载。
再也不用重启100+台Jmeter代理端而烦恼了。