CallmeJack 发表于 2018-2-8 13:40:41

Jmeter 插件开发

一. 配置源码

下载源码包 地址
导入源码包,我这里使用的工具IntelliJ。直接File->open就行。导入后的项目目录如下图:

下载jar包。jar包下载下来的地址为:/lib

添加jar包。File->Project Structure->Libraries
install

运行 src->core->apache.jmeter->NewDriver
public static void main(String[] args) {

    Thread.currentThread().setContextClassLoader(loader);
    if (System.getProperty("log4j.configuration") == null) {// $NON-NLS-1$ $NON-NLS-2$
      File conf = new File(jmDir, "bin" + File.separator + "log4j.conf");// $NON-NLS-1$ $NON-NLS-2$
      System.setProperty("log4j.configuration", "file:" + conf);
    }

    try {
      Class<?> initialClass = loader.loadClass("org.apache.jmeter.JMeter");// $NON-NLS-1$
      Object instance = initialClass.newInstance();
      Method startup = initialClass.getMethod("start", new Class[] { new String.getClass() });// $NON-NLS-1$
      startup.invoke(instance, new Object[] { args });
    } catch(Throwable e){
      e.printStackTrace();
      System.err.println("JMeter home directory was detected as: "+jmDir);
    }
}从上述代码中我们可以看出,其实之际上调用的是src->core->apache.jmeter->Jmeter 的start() 方法。
而当我们打开Jmeter的Gui时,实际上调用的用的是src->core->apache.jmeter->Jmeter 的startGui() 方法
private void startGui(String testFile) {
      String jMeterLaf = LookAndFeelCommand.getJMeterLaf();
      try {
            UIManager.setLookAndFeel(jMeterLaf);
      } catch (Exception ex) {
            log.warn("Could not set LAF to:"+jMeterLaf, ex);
      }

      PluginManager.install(this, true);

      JMeterTreeModel treeModel = new JMeterTreeModel();
      JMeterTreeListener treeLis = new JMeterTreeListener(treeModel);
      final ActionRouter instance = ActionRouter.getInstance();
      instance.populateCommandMap();//这个方法会去寻找<your project>/lib/ext 下所有的jar
      treeLis.setActionHandler(instance);
      // NOTUSED: GuiPackage guiPack =
      GuiPackage.getInstance(treeLis, treeModel);
      MainFrame main = new MainFrame(treeModel, treeLis);
      ComponentUtil.centerComponentInWindow(main, 80);
      main.setVisible(true);
      instance.actionPerformed(new ActionEvent(main, 1, ActionNames.ADD_ALL));
      if (testFile != null) {
            try {
                File f = new File(testFile);
                log.info("Loading file: " + f);
                FileServer.getFileServer().setBaseForScript(f);

                HashTree tree = SaveService.loadTree(f);

                GuiPackage.getInstance().setTestPlanFile(f.getAbsolutePath());

                Load.insertLoadedTree(1, tree);
            } catch (ConversionException e) {
                log.error("Failure loading test file", e);
                JMeterUtils.reportErrorToUser(SaveService.CEtoString(e));
            } catch (Exception e) {
                log.error("Failure loading test file", e);
                JMeterUtils.reportErrorToUser(e.toString());
            }
      } else {
            JTree jTree = GuiPackage.getInstance().getMainFrame().getTree();
            TreePath path = jTree.getPathForRow(0);
            jTree.setSelectionPath(path);
            FocusRequester.requestFocus(jTree);
      }
    }二.开发sampler

JMeter加载插件的机制比较简单,扫描扩展下的的所有实现了JMeterGUIComponent和TestBean接口的
类,然后进行初始化。
ClassFinder.findClassesThatExtend(
    JMeterUtils.getSearchPaths(),
    new Class[] {JMeterGUIComponent.class, TestBean.class }
在getSearchPaths()在这个方法中,它寻找的路径是/lib/ext,所以要确保你开发的插件的jar存在与这
个路径中。
public static String[] getSearchPaths() {
      String p = JMeterUtils.getPropDefault("search_paths", null); // $NON-NLS-1$
      String[] result = new String;

      if (p != null) {
            String[] paths = p.split(";"); // $NON-NLS-1$
            result = new String;
            System.arraycopy(paths, 0, result, 1, paths.length);
      }
      result = getJMeterHome() + "/lib/ext"; // $NON-NLS-1$
      return result;
    }jmeter提供了example。src/examples,所以在写之前 可以多参考一下

在src/components/sampler/gui 下新建SmaplerGui,继承AbstractSamplerGui 类。 ```java package org.apache.jmeter.sampler.gui;
import com.btcc.fix.TestUser;
import net.sourceforge.jdatepicker.JDateComponentFactory;
import net.sourceforge.jdatepicker.JDatePanel;
import net.sourceforge.jdatepicker.impl.UtilDateModel;
import org.apache.jmeter.gui.util.HorizontalPanel;
import org.apache.jmeter.gui.util.VerticalPanel;
import org.apache.jmeter.sampler.FixSmapler;
import org.apache.jmeter.sampler.MessageProvider;
import org.apache.jmeter.samplers.gui.AbstractSamplerGui;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
import quickfix.btcc.Message;

import javax.swing.;
import java.awt.;
import java.awt.event.*;
import java.text.SimpleDateFormat;
import java.util.Date;

import static javax.swing.BorderFactory.createTitledBorder;

/**

Created by sara on 12/10/2016.
*/
public class FixSmaplerGui extends AbstractSamplerGui {

private static final Logger log = LoggingManager.getLoggerForClass();

// 布局定义
private JTextField requestNameText = null;
private JTextField hostText = null;
private JTextField portText = null;
private JCheckBox sslCheckBox = null;

public FixSmaplerGui(){
super();
init();
}

//用这个方法将fixSmapler的数据设置到你的gui中
@Override
public void configure(TestElement element) {

super.configure(element);
FixSmapler fixSmapler = (FixSmapler)element;
hostText.setText(fixSmapler.getHost());
portText.setText(fixSmapler.getPort());
sslCheckBox.setSelected(fixSmapler.getSsl());

}

private void init() {
setLayout(new BorderLayout(0, 5));
setBorder(makeBorder());
add(createDataPanel(),BorderLayout.CENTER);
}

// 这个方法是用来创建你自己的元素布局的
private JPanel createDataPanel(){
final JPanel settingPanel = new VerticalPanel(5, 0);
settingPanel.setBorder(makeBorder());
settingPanel.add(makeTitlePanel());

// host
JPanel hostPanel = new HorizontalPanel();
hostPanel.setBorder(createTitledBorder("Host/port"));

JLabel hostLable = new JLabel("Host:");
this.hostText = new JTextField(15);
hostLable.setLabelFor(hostText);
hostPanel.add(hostLable);
hostPanel.add(hostText);

JLabel portLable = new JLabel("Port:");
portText = new JTextField(15);
portLable.setLabelFor(portText);
hostPanel.add(portLable);
hostPanel.add(portText);

JLabel sslLabel = new JLabel("SSL");
sslCheckBox = new JCheckBox();
sslLabel.setLabelFor(sslCheckBox);
hostPanel.add(sslLabel);
hostPanel.add(sslCheckBox);
settingPanel.add(hostPanel);
return settingPanel;

}

// 创建新的sampler。并且将它传给你创建的modifyTestElement(TestElement)方法。
@Override
public TestElement createTestElement() {

TestElement sampler = new FixSmapler();
modifyTestElement(sampler);
return sampler;
}

// 这个方法应该返回代表的component的title/name的名字。fix_sampler_title必须被写进jmeter 的messages.properties文件中。
@Override
public String getLabelResource() {
// TODO Auto-generated method stub
return "fix_sampler_title"; // $NON-NLS-1$
}

// 这个方法是用来将数据从你的gui传到TestElement.这个方法和configure()方法在逻辑上是相反的
@Override
public void modifyTestElement(TestElement element) {
super.configureTestElement(element);
FixSmapler smapler = (FixSmapler) element;
smapler.setHost(hostText.getText());
smapler.setPort(portText.getText());
smapler.setSsl(sslCheckBox.isSelected());

}

// 这个方法是用来在你创建新的sampler时,清除数据的。
@Override
public void clearGui() {
super.clearGui();
hostText.setText("");
portText.setText("");
sslCheckBox.setSelected(false);

}
}

CallmeJack 发表于 2018-2-8 13:41:48

当是在gui上创建一个sampler,其调用的顺序是**clearGui()->createTestElement()->modifyTestElement()->configure()**

2. 在src/components/sampler 下新建Smapler,继承AbstractSampler 类。
```java
import com.btcc.fix.FixClient;
import com.btcc.fix.TestClient;
import org.apache.jmeter.samplers.AbstractSampler;
import org.apache.jmeter.samplers.Entry;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testelement.property.BooleanProperty;
import org.apache.jmeter.testelement.property.IntegerProperty;
import org.apache.jmeter.testelement.property.StringProperty;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;


/**
* Created by sara on 12/10/2016.
*/
public class FixSmapler extends AbstractSampler {

    private static final Logger log = LoggingManager.getLoggerForClass();


    private static final String HOST = "Fix.host"; //$NON-NLS-1$
    private static final String PORT = "Fix.port"; //$NON-NLS-1$
    private static final String SSL = "Fix.ssl"; //$NON-NLS-1$

    private static TestClient client = null;
    private static Message request= null;


    private static AtomicInteger classCount = new AtomicInteger(0); // keep track of classes created

    public FixSmapler() {
       classCount.incrementAndGet();
      trace("FixSmapler()");
    }

    // 这个方法主要是用来执行和收集执行后的result数据的
    @Override
    public SampleResult sample(Entry entry) {
      trace("sample()");
      SampleResult res = new SampleResult();
      boolean isOK = false;

      TestClient c = getClient();
      // 设置结果的名称
      res.setSampleLabel(getTitle());

      // 设置request数据
      res.setSamplerData(request.toString());
      res.sampleStart();

      final CountDownLatch responseLatch = new CountDownLatch(1);

      StringBuffer sb = new StringBuffer();
      FixClient.Callback callback = new FixClient.Callback() {
            @Override
            public void onMessage(quickfix.Message message) {

                String[] fds = message.toString().split("\\001");

                for(String fd:fds){
                  sb.append(fd).append("\r\n");
                }

                responseLatch.countDown();
            }
      };

      try{

            int count = 0;
            while (!c.connect()){
                Thread.sleep(1000);

                count++;

                if(count >=10){
                  throw new Exception("Fix server can't connect");
                }
            }

            c.send(request,callback);
            responseLatch.await();
            //设置response数据
            res.setResponseMessage(sb.toString());
            byte[] bytes = sb.toString().getBytes();
            res.setResponseData(bytes);
            res.setDataType(SampleResult.TEXT);
            res.setResponseCodeOK();
            res.setResponseMessage("OK");
            isOK = true;
      }catch (Exception e){
            log.error("send fail: ".concat(e.toString()));
            res.setResponseCode("500");// $NON-NLS-1$
            res.setResponseData(e.toString());
      }finally {
            c.removeCallback(callback);
            c.disconnect();
      }

      res.sampleEnd();

      res.setSuccessful(isOK);
      returnres;
    }执行 ant install
安装过后,你直接运行NewDriver 和 /bin/jmeter 都是可以的。
截图



梦想家 发表于 2018-2-28 17:13:08

支持分享

Miss_love 发表于 2020-12-30 08:35:46

感谢分享
页: [1]
查看完整版本: Jmeter 插件开发