JMeter设计模式

来源:互联网 发布:ubuntu trusty 编辑:程序博客网 时间:2024/04/29 13:59

JMeter是一个纯Java项目,最早用于测试tomcat,版本2.13-SNAPSHO源码含1,083 个 Java文件,185行/文件,共计201,178行代码,其中core目录含61,972行Java代码,这是一个非常庞大而又历史悠久的项目。有时候,面对一个非常复杂的Java项目的源码时,我们可以先对里面涉及到23种涉及模式的类进行隔离分析,这样剩余代码也就不难理解了吧。

1 单例模式

JMeter采用了三种线程安全方式实现单例模式。包括在内部定义一个单例的静态私有Holder类、直接用synchronized修饰getInstance()和双重校验锁。

1.1 JMeterUtils -- 定义一个内部静态单例Holder类

用私有静态类LazyPatternCacheHolder作为单例的容器,保证在类加载时完成实例化

  

private static class LazyPatternCacheHolder { 
      public static final PatternCacheLRU INSTANCE = new PatternCacheLRU( 
              getPropDefault("oro.patterncache.size",1000), // $NON-NLS-1$ 
              new Perl5Compiler()); 
   }

  // 获取单例

public static PatternCacheLRU getPatternCache() { 
      return LazyPatternCacheHolder.INSTANCE;
 
  }

1.2 SSLManager -- 用synchronized修饰getInstance()

/** Singleton instance of the manager */
    //@GuardedBy("this")
    private static SSLManager manager;
/**
 * Resets the SSLManager so that we can create a new one with a new keystore
 */
    public static synchronized void reset() {
        SSLManager.manager = null;
    }
/** 
     * Protected Constructor to remove the possibility of directly instantiating 
     * this object. Create the SSLContext, and wrap all the X509KeyManagers with 
     * our X509KeyManager so that we can choose our alias. 
     */ 
    protected SSLManager() { 
    }

    /** 
     * Static accessor for the SSLManager object. The SSLManager is a singleton.     *
     * @return the singleton {@link SSLManager}
     */
    public static final synchronized SSLManager getInstance() {
        if (null == SSLManager.manager) {
            SSLManager.manager = new JsseSSLManager(null);
        }
        return SSLManager.manager;
    }

1.3 XPathUtil -- 用synchronized修饰getInstance()

//@GuardedBy("this") 
    private static DocumentBuilderFactory documentBuilderFactory;
    /**
     * Returns a suitable document builder factory.
     * Caches the factory in case the next caller wants the same options.
     *
     * @param validate should the parser validate documents?
     * @param whitespace should the parser eliminate whitespace in element content?
     * @param namespace should the parser be namespace aware?     *
     * @return javax.xml.parsers.DocumentBuilderFactory
     */
    private static synchronized DocumentBuilderFactory makeDocumentBuilderFactory(boolean validate, boolean whitespace,
            boolean namespace) { 
        if (XPathUtil.documentBuilderFactory == null || documentBuilderFactory.isValidating() != validate
                || documentBuilderFactory.isNamespaceAware() != namespace
                || documentBuilderFactory.isIgnoringElementContentWhitespace() != whitespace) {
            // configure the document builder factory
            documentBuilderFactory = DocumentBuilderFactory.newInstance();
            documentBuilderFactory.setValidating(validate);
            documentBuilderFactory.setNamespaceAware(namespace);
            documentBuilderFactory.setIgnoringElementContentWhitespace(whitespace);
        }
        return XPathUtil.documentBuilderFactory;
    }

1.4 ObjectFactory -- 定义一个内部静态单例Holder类

public class ObjectFactory {
    private static class ObjectFactoryHolder {
        static final ObjectFactory FACTORY = new ObjectFactory();
      }

1.5 ActionRouter -- 双重校验锁

private static final Object LOCK = new Object();
private static volatile ActionRouter router;
    /**
     * Gets the Instance attribute of the ActionRouter class     *
     * @return The Instance value
     */
    public static ActionRouter getInstance() {
        if (router == null) {
            synchronized (LOCK) {
                if(router == null) {
                    router = new ActionRouter();
                    router.populateCommandMap();
                }
            }
        }
        return router;
    }

2 工厂模式

2.1 ObjectFactory -- 简单工厂

public class ObjectFactory {
    private static class ObjectFactoryHolder {
        static final ObjectFactory FACTORY = new ObjectFactory();
      }
    private final Parser PARSER;
 
    protected ObjectFactory() {
        super();
        PARSER = new MonitorParser(this);
    }
 
    public static ObjectFactory getInstance() {
        return ObjectFactoryHolder.FACTORY;
    }
 
    public Status parseBytes(byte[] bytes) {
        return PARSER.parseBytes(bytes);
    } 
 
    public Status parseString(String content) { 
        return PARSER.parseString(content); 
    } 
 
    public Status parseSampleResult(SampleResult result) {
        return PARSER.parseSampleResult(result); 
    }
 
    public Status createStatus() { 
        return new StatusImpl(); 
    } 
    public Connector createConnector() {
        return new ConnectorImpl(); 
    } 
 
    public Jvm createJvm() { 
        return new JvmImpl(); 
    } 
 
    public Memory createMemory() { 
        return new MemoryImpl(); 
    } 
 
    public RequestInfo createRequestInfo() { 
        return new RequestInfoImpl(); 
    }
 
 
    public ThreadInfo createThreadInfo() { 
        return new ThreadInfoImpl(); 
    } 
 
    public Worker createWorker() { 
        return new WorkerImpl(); 
    }
 
 
    public Workers createWorkers() { 
        return new WorkersImpl(); 
    } 
 
    protected static class MonitorParser extends ParserImpl { 
        public MonitorParser(ObjectFactory factory) { 
            super(factory); 
        } 
    } 
}

2.2 MenuFactory--工厂方法

......
     public static JPopupMenu getDefaultControllerMenu() { 
        JPopupMenu pop = new JPopupMenu(); 
        pop.add(MenuFactory.makeMenus(MENU_ADD_CONTROLLER, 
                JMeterUtils.getResString("add"),// $NON-NLS-1$ 
                ActionNames.ADD)); 
        pop.add(makeMenus(MENU_PARENT_CONTROLLER, 
                JMeterUtils.getResString("insert_parent"),// $NON-NLS-1$ 
                ActionNames.ADD_PARENT)); 
        pop.add(makeMenus(MENU_PARENT_CONTROLLER, 
                JMeterUtils.getResString("change_parent"),// $NON-NLS-1$ 
                ActionNames.CHANGE_PARENT)); 
        MenuFactory.addEditMenu(pop, true); 
        MenuFactory.addFileMenu(pop); 
        return pop; 
    } 
 
    public static JPopupMenu getDefaultSamplerMenu() { 
        JPopupMenu pop = new JPopupMenu(); 
        pop.add(MenuFactory.makeMenus(MENU_ADD_SAMPLER, 
                JMeterUtils.getResString("add"),// $NON-NLS-1$ 
                ActionNames.ADD)); 
        pop.add(makeMenus(MENU_PARENT_SAMPLER, 
                JMeterUtils.getResString("insert_parent"),// $NON-NLS-1$ 
                ActionNames.ADD_PARENT)); 
        MenuFactory.addEditMenu(pop, true); 
        MenuFactory.addFileMenu(pop); 
        return pop; 
    } 
 
    public static JPopupMenu getDefaultConfigElementMenu() { 
        JPopupMenu pop = new JPopupMenu(); 
        MenuFactory.addEditMenu(pop, true); 
        MenuFactory.addFileMenu(pop); 
        return pop; 
    } 
 
    public static JPopupMenu getDefaultVisualizerMenu() { 
        JPopupMenu pop = new JPopupMenu(); 
        MenuFactory.addEditMenu(pop, true); 
        MenuFactory.addFileMenu(pop); 
        return pop; 
    } 
 
    public static JPopupMenu getDefaultTimerMenu() { 
        JPopupMenu pop = new JPopupMenu(); 
        MenuFactory.addEditMenu(pop, true); 
        MenuFactory.addFileMenu(pop); 
        return pop;
    }
......

1.3 HTTPSamplerFactory -- 工厂方法

 

/** 
     * Create a new instance of the required sampler type      * 
     * @param alias HTTP_SAMPLER or HTTP_SAMPLER_APACHE or IMPL_HTTP_CLIENT3_1 or IMPL_HTTP_CLIENT4 
     * @return the appropriate sampler 
     * @throws UnsupportedOperationException if alias is not recognised 
     */
 
    public static HTTPSamplerBase newInstance(String alias) { 
        if (alias ==null || alias.length() == 0) { 
            return new HTTPSamplerProxy(); 
        }
 
        if (alias.equals(HTTP_SAMPLER_JAVA) || alias.equals(IMPL_JAVA)) { 
            return new HTTPSamplerProxy(IMPL_JAVA); 
        }
 
        if (alias.equals(HTTP_SAMPLER_APACHE) || alias.equals(IMPL_HTTP_CLIENT3_1)) { 
            return new HTTPSamplerProxy(IMPL_HTTP_CLIENT3_1); 
        }
 
        if (alias.equals(IMPL_HTTP_CLIENT4)) { 
            return new HTTPSamplerProxy(IMPL_HTTP_CLIENT4); 
        }
 
        throw new IllegalArgumentException("Unknown sampler type: '" + alias+"'"); 
    }
 
    public static HTTPAbstractImpl getImplementation(String impl, HTTPSamplerBase base){ 
        if (HTTPSamplerBase.PROTOCOL_FILE.equals(base.getProtocol())) { 
            return new HTTPFileImpl(base);
         } 
        if (JOrphanUtils.isBlank(impl)){ 
            impl = DEFAULT_CLASSNAME; 
        }
 
        if (IMPL_JAVA.equals(impl) || HTTP_SAMPLER_JAVA.equals(impl)) { 
            return new HTTPJavaImpl(base); 
        } else if (IMPL_HTTP_CLIENT3_1.equals(impl) || HTTP_SAMPLER_APACHE.equals(impl)) { 
            return new HTTPHC3Impl(base);          
 
        } else if (IMPL_HTTP_CLIENT4.equals(impl)) { 
            return new HTTPHC4Impl(base); 
        } else { 
            throw new IllegalArgumentException("Unknown implementation type: '"+impl+"'"); 
        } 
    }

3 组合模式

定义:将对象组合成树形结构以表示部分整体的关系,Composite使得用户对单个对象和组合对象的使用具有一致性。

3.1 TestElement -- 测试元件接口

public interface TestElement extends Cloneable  // 一般组合模式的接口都有实现对象克隆接口


测试计划、逻辑控制器、样本、线程组等等实现了测试元件接口。单个测试计划由若干测试元件对象组合而成。例如逻辑控制器对象可以相互嵌套,样本和逻辑控制器可以相互嵌套。这种设计模式,决定了测试计划内存数据结构是一颗树。

3.3 JMeterGUIComponent

JMeter的GUI组件显然也是一个组合模式。这些GUI组件主要是用于测试元件的配置,测试元件类一般与GUI组件类,一一对应。

0 0