JMeter设计模式

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组件类,一一对应。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值