一. 配置源码

  1. 下载源码包 地址
  2. 导入源码包,我这里使用的工具 IntelliJ。直接 File->open 就行。导入后的项目目录如下图: 项目目录
  3. 下载 jar 包。jar 包下载下来的地址为:/lib
    下载jar
  4. 添加 jar 包。File->Project Structure->Libraries
  5. install install
  6. 运行 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[0].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[1];

        if (p != null) {
            String[] paths = p.split(";"); // $NON-NLS-1$
            result = new String[paths.length + 1];
            System.arraycopy(paths, 0, result, 1, paths.length);
        }
        result[0] = getJMeterHome() + "/lib/ext"; // $NON-NLS-1$
        return result;
    }

jmeter 提供了 example。src/examples,所以在写之前 可以多参考一下

  1. 在 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;

/**

当是在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);
        return  res;
    }
  1. 执行 ant install
    安装过后,你直接运行 NewDriver 和 /bin/jmeter 都是可以的。

  2. 截图fixSampler


↙↙↙阅读原文可查看相关链接,并与作者交流