`

cglib相关性能测试对比

 
阅读更多

转载:http://www.iteye.com/topic/801577

很多同学提出,因中文文档缺乏,导致对文章中的介绍看的不是很明白,更多的只是想了解具体的使用即可。所以趁势写了这篇博文,主要是将cglib中的几个工具类和常用的Reflect ,BeanUtils做一个对比,顺便也介绍一下cglib的相关用法,一举两得,望大家多多支持。

 

正题:

1.  首先定义一份Pojo Bean ,后续的测试主要围绕这个进行。

 

 

Java代码  收藏代码
  1. public static class CopyBean {  
  2.   
  3.         private int        intValue;  
  4.         private boolean    boolValue;  
  5.         private float      floatValue;  
  6.         private double     doubleValue;  
  7.         private long       longValue;  
  8.         private char       charValue;  
  9.         private byte       byteValue;  
  10.         private short      shortValue;  
  11.         private Integer    integerValue;  
  12.         private Boolean    boolObjValue;  
  13.         private Float      floatObjValue;  
  14.         private Double     doubleObjValue;  
  15.         private Long       longObjValue;  
  16.         private Short      shortObjValue;  
  17.         private Byte       byteObjValue;  
  18.         private BigInteger bigIntegerValue;  
  19.         private BigDecimal bigDecimalValue;  
  20.         private String     stringValue;  
  21. ......// 一堆的setter/getter方法  
  22. }  

 

 说明: 该copyBean基本包含了java的所有原型对象,基本对象,和常用的BigDecimal,BigInteger,总共17个属性。

 

2.  定义测试模板 (模板模式)

 

   定义一个TestCallback接口。

 

Java代码  收藏代码
  1. interface TestCallback {  
  2.   
  3.     String getName();  
  4.   
  5.     CglibPerformanceTest.CopyBean call(CglibPerformanceTest.CopyBean source);  
  6. }  

 

 

   定义测试的模板方法 

   private static final DecimalFormat integerFormat = new DecimalFormat("#,###");

Java代码  收藏代码
  1. public static void testTemplate(TestCallback callback, CopyBean source, int count) {  
  2.         int warmup = 10;  
  3.         // 先进行预热,加载一些类,避免影响测试  
  4.         for (int i = 0; i < warmup; i++) {  
  5.             callback.call(source);  
  6.         }  
  7.         restoreJvm(); // 进行GC回收  
  8.         // 进行测试  
  9.         long start = System.nanoTime();  
  10.         for (int i = 0; i < count; i++) {  
  11.             callback.call(source);  
  12.         }  
  13.         long nscost = (System.nanoTime() - start);  
  14.         System.out.println(callback.getName() + " total cost=" + integerFormat.format(nscost) + "ns , each cost="  
  15.                            + nscost / count  + "ns");  
  16.         restoreJvm();// 进行GC回收  
  17.   
  18.     }  

 

 

 说明:

 

  • 为了测试更加精确,避免因为在一次的循环中进行处理,jvm内存,GC,Class装载对测试的影响,有一个warmup的过程,先执行少量的测试方法,这里是执行10次
  • 避免jvm内存GC对测试id影响,这里有restoreJvm强制进行一次jvm GC

   restoreJvm相关方法:

   private static void restoreJvm() {
Java代码  收藏代码
  1.     int maxRestoreJvmLoops = 10;  
  2.     long memUsedPrev = memoryUsed();  
  3.     for (int i = 0; i < maxRestoreJvmLoops; i++) {  
  4.         System.runFinalization();  
  5.         System.gc();  
  6.   
  7.         long memUsedNow = memoryUsed();  
  8.         //  如果多次GC后内存稳定了,就退出   
  9.         if ((ManagementFactory.getMemoryMXBean().getObjectPendingFinalizationCount() == 0)  
  10.             && (memUsedNow >= memUsedPrev)) {  
  11.             break;  
  12.         } else {  
  13.             memUsedPrev = memUsedNow;  
  14.         }  
  15.     }  
  16. }  
  17.   
  18. private static long memoryUsed() {  
  19.     Runtime rt = Runtime.getRuntime();  
  20.     return rt.totalMemory() - rt.freeMemory();  
  21. }  

 

3.  准备原始的CopyBean数据

 

Java代码  收藏代码
  1. private static CopyBean getBean() {  
  2.         CopyBean bean = new CopyBean();  
  3.         bean.setIntValue(1);  
  4.         bean.setBoolValue(false);  
  5.         bean.setFloatValue(1.0f);  
  6.         bean.setDoubleValue(1.0d);  
  7.         bean.setLongValue(1l);  
  8.         bean.setCharValue('a');  
  9.         bean.setShortValue((short1);  
  10.         bean.setByteValue((byte1);  
  11.         bean.setIntegerValue(new Integer("1"));  
  12.         bean.setBoolObjValue(new Boolean("false"));  
  13.         bean.setFloatObjValue(new Float("1.0"));  
  14.         bean.setDoubleObjValue(new Double("1.0"));  
  15.         bean.setLongObjValue(new Long("1"));  
  16.         bean.setShortObjValue(new Short("1"));  
  17.         bean.setByteObjValue(new Byte("1"));  
  18.         bean.setBigIntegerValue(new BigInteger("1"));  
  19.         bean.setBigDecimalValue(new BigDecimal("1"));  
  20.         bean.setStringValue("1");  
  21.         return bean;  
  22.     }  

 

 

4. 执行相关测试

测试环境说明:

 

  • 操作系统 Linux ccbu-156-49 2.6.18-131.el5.customxen #1 SMP Tue Sep 15 15:46:11 CST 2009 x86_64 x86_64 x86_64 GNU/Linux
  • 虚拟8cpu , 5G内存
  • jdk  1.6.0_18
  • jvm 参数 
  • Jvm参数代码  收藏代码
    1. -server -Xmx2g -Xms2g -Xmn512m -XX:PermSize=196m -Xss256k -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70  
     

第一测试主要是一个对象的全部属性进行拷贝

  • BeanCopier  (cglib)
  • PropertyUtils (apache-common)
  • BeanUtils (apache-common)
 
1.  BeanCopier  (cglib)

 

  • Java代码  收藏代码
    1. // beanCopier测试  
    2.      final BeanCopier beanCopier = BeanCopier.create(CopyBean.class, CopyBean.classfalse);  
    3.         final CopyBean beanCopierTarget = new CopyBean();//new一次,避免new对象产生的代价影响测试结果  
    4.         testTemplate(new TestCallback() {  
    5.   
    6.             public String getName() {  
    7.                 return "BeanCopier";  
    8.             }  
    9.   
    10.             public CopyBean call(CopyBean source) {  
    11.                 beanCopier.copy(source, beanCopierTarget, null);  
    12.                 return beanCopierTarget;  
    13.             }  
    14.         }, bean, testCount);  
2. PropertyUtils (apache-common)
  • Java代码  收藏代码
    1. <span style="background-color: rgba(0, 0, 0, 0);">// PropertyUtils测试  
    2.         final CopyBean propertyUtilsTarget = new CopyBean();  
    3.         testTemplate(new TestCallback() {  
    4.   
    5.             public String getName() {  
    6.                 return "PropertyUtils";  
    7.             }  
    8.   
    9.             public CopyBean call(CopyBean source) {  
    10.                 try {  
    11.                     PropertyUtils.copyProperties(propertyUtilsTarget, source);  
    12.                 } catch (Exception e) {  
    13.                     e.printStackTrace();  
    14.                 }  
    15.                 return propertyUtilsTarget;  
    16.             }  
    17.   
    18.         }, bean, testCount);</span>  
3. BeanUtils (apache-common)
    • Java代码  收藏代码
      1. <span style="background-color: rgba(0, 0, 0, 0);">// BeanUtils测试  
      2.         final CopyBean beanUtilsTarget = new CopyBean();  
      3.         testTemplate(new TestCallback() {  
      4.   
      5.             public String getName() {  
      6.                 return "BeanUtils";  
      7.             }  
      8.   
      9.             public CopyBean call(CopyBean source) {  
      10.                 try {  
      11.                     BeanUtils.copyProperties(beanUtilsTarget, source);  
      12.                 } catch (Exception e) {  
      13.                     e.printStackTrace();  
      14.                 }  
      15.                 return beanUtilsTarget;  
      16.             }  
      17.   
      18.         }, bean, testCount);</span>  

 

测试结果: 

 

测试次数:testCount = 1000 * 1000 = 100万次

  • BeanCopier total cost=36,626,000ns , each cost=36ns
  • PropertyUtils total cost=18,173,767,000ns , each cost=18173ns
  • BeanUtils total cost=31,236,079,000ns , each cost=31236ns
从这个结果可以看出, BeanCopier是PropertyUtils的504倍, PropertyUtils是BeanUtils的1.71倍, BeanCopier是PropertyUtils的861.84倍,差了近3个数量级。
 

第二测试主要是一个对象的单个属性进行拷贝 

  • BulkBean (cglib)
  • BeanMap (cglib)
  • FastClass/FastMethod  (cglib)
  • 未处理的jdk reflect (jdk)
  • 处理的jdk reflect (jdk)
1. BulkBean 
Java代码  收藏代码
  1. // 测试BulkBean  
  2.         final BulkBean bulkBean = BulkBean.create(bean.getClass(), new String[] { getMethodName },  
  3.                                                   new String[] { setMethodName }, new Class[] { Integer.class });  
  4.         final CopyBean bulkBeanTarget = new CopyBean();  
  5.         testTemplate(new TestCallback() {  
  6.   
  7.             @Override  
  8.             public String getName() {  
  9.                 return "BulkBean";  
  10.             }  
  11.   
  12.             @Override  
  13.             public CopyBean call(CopyBean source) {  
  14.                 Object[] result = bulkBean.getPropertyValues(source); // 先调用getter  
  15.                 bulkBean.setPropertyValues(bulkBeanTarget, result); // 再调用setter  
  16.                 return bulkBeanTarget;  
  17.             }  
  18.   
  19.         }, bean, testCount);  
 
2. BeanMap
 
Java代码  收藏代码
  1. // 测试BeanMap  
  2.         final BeanMap sourceMap = BeanMap.create(bean); // 预先创建对象  
  3.         final BeanMap targetMap = BeanMap.create(new CopyBean());  
  4.         final CopyBean beanMapTarget = new CopyBean();  
  5.         testTemplate(new TestCallback() {  
  6.   
  7.             @Override  
  8.             public String getName() {  
  9.                 return "BeanMap";  
  10.             }  
  11.   
  12.             @Override  
  13.             public CopyBean call(CopyBean source) {  
  14.                 targetMap.setBean(beanMapTarget); // 将目标对象设置于beanMap  
  15.                 Object obj = sourceMap.get(fieldName);  
  16.                 targetMap.put(fieldName, obj);  
  17.                 return beanMapTarget;  
  18.             }  
  19.   
  20.         }, bean, testCount);  
 
 3. FastClass/FastMethod
Java代码  收藏代码
  1. // 测试FastClass  
  2.         final FastClass fastClass = FastClass.create(bean.getClass());  
  3.         final FastMethod setFastMetod = fastClass.getMethod(setMethodName, new Class[] { Integer.class });  
  4.         final FastMethod getFastMetod = fastClass.getMethod(getMethodName, new Class[] {});  
  5.         final CopyBean fastClassTarget = new CopyBean();  
  6.         testTemplate(new TestCallback() {  
  7.   
  8.             @Override  
  9.             public String getName() {  
  10.                 return "FastClass";  
  11.             }  
  12.   
  13.             @Override  
  14.             public CopyBean call(CopyBean source) {  
  15.   
  16.                 try {  
  17.                     Object field = getFastMetod.invoke(source, new Object[] {});// 调用get方法  
  18.                     setFastMetod.invoke(fastClassTarget, new Object[] { field });// 调用set方法赋值  
  19.                 } catch (Exception e) {  
  20.                     e.printStackTrace();  
  21.                 }  
  22.   
  23.                 return fastClassTarget;  
  24.             }  
  25.   
  26.         }, bean, testCount);  
 
4.  未处理的jdk reflect
Java代码  收藏代码
  1. try {  
  2.             // 进行method对象cache,真实应用中一般都会cache method对象  
  3.             final Method getMethod = bean.getClass().getMethod(getMethodName, new Class[] {});  
  4.             final Method setMethod = bean.getClass().getMethod(setMethodName, new Class[] { Integer.class });  
  5.             // 测试未优化过的Reflect  
  6.             final CopyBean reflect1Target = new CopyBean();  
  7.             testTemplate(new TestCallback() {  
  8.   
  9.                 @Override  
  10.                 public String getName() {  
  11.                     return "未优化过的Reflect";  
  12.                 }  
  13.   
  14.                 @Override  
  15.                 public CopyBean call(CopyBean source) {  
  16.                     try {  
  17.                         Object field = getMethod.invoke(source, new Object[] {});  
  18.                         setMethod.invoke(reflect1Target, new Object[] { field });  
  19.                     } catch (Exception e) {  
  20.                         e.printStackTrace();  
  21.                     }  
  22.                     return reflect1Target;  
  23.                 }  
  24.   
  25.             }, bean, testCount);  
  26.   
  27.         } catch (Exception e1) {  
  28.             e1.printStackTrace();  
  29.         }  
  30.   
  31.     }  
 
 
5. 处理过的jdk reflect
Java代码  收藏代码
  1. try {  
  2.             // 进行method对象cache,真实应用中一般都会cache method对象  
  3.             final Method getMethod = bean.getClass().getMethod(getMethodName, new Class[] {});  
  4.             final Method setMethod = bean.getClass().getMethod(setMethodName, new Class[] { Integer.class });  
  5.             // 测试优化过的Reflect  
  6.             getMethod.setAccessible(true);// 设置不进行access权限检查  
  7.             setMethod.setAccessible(true);// 设置不进行access权限检查  
  8.             final CopyBean reflect2Target = new CopyBean();  
  9.             testTemplate(new TestCallback() {  
  10.   
  11.                 @Override  
  12.                 public String getName() {  
  13.                     return "优化过的Reflect";  
  14.                 }  
  15.   
  16.                 @Override  
  17.                 public CopyBean call(CopyBean source) {  
  18.                     try {  
  19.                         Object field = getMethod.invoke(source, new Object[] {});  
  20.                         setMethod.invoke(reflect2Target, new Object[] { field });  
  21.                     } catch (Exception e) {  
  22.                         e.printStackTrace();  
  23.                     }  
  24.                     return reflect2Target;  
  25.                 }  
  26.   
  27.             }, bean, testCount);  
  28.         } catch (Exception e1) {  
  29.             e1.printStackTrace();  
  30.         }  
 

 

 

测试结果:  

 

测试次数:testCount = 1000 * 1000 * 100 = 1亿次

  • BulkBean total cost=2,125,759,000ns , each cost=21ns
  • BeanMap total cost=2,730,912,000ns , each cost=27ns
  • FastClass total cost=2,576,470,000ns , each cost=25ns
  • 未处理过的Reflect total cost=2,882,755,000ns , each cost=28ns
  • 处理过的Reflect total cost=2,792,828,000ns , each cost=27ns
测试结果,性能相差不多,差距不大,这也可以说明jdk对reflect调用的优化已经做的很棒了。
分享到:
评论

相关推荐

    cglib动态代理

    8. **性能对比**:相对于JDK的动态代理,CGLib在某些场景下性能更优,因为它避免了接口调用的额外开销。然而,由于涉及到字节码操作,CGLib在初始化阶段可能比JDK代理慢。 9. **使用示例**:创建一个动态代理通常...

    cglib-3.2.4.jar

    五、CGlib与Java反射动态代理的对比 虽然Java自带的反射API提供了简单的动态代理实现,但仅限于实现了接口的类。对于没有接口的类,CGlib提供了一种更灵活的解决方案。然而,CGlib的性能通常稍逊于Java反射API,...

    Java 动态代理详解(代理模式+静态代理+JDK动态代理+CGLIB动态代理)

    Java 动态代理是 Java 编程语言中的一种强大工具,广泛应用于 Spring AOP、Hibernate 数据查询、测试框架的后端 mock、RPC 远程调用、Java 注解对象获取、日志、用户鉴权、全局性异常处理、性能监控等领域。...

    JDKProxy:用来理解jdk基于接口的动态代理和cglib基于类代理区别的demo

    本示例"JDKProxy"着重于对比两种常见的动态代理技术:JDK的接口代理和CGLIB的类代理。这两种代理方式在Java应用程序中都有广泛的应用,例如在AOP(面向切面编程)框架如Spring中。 首先,我们来深入了解一下JDK的...

    动态代理

    - **CGLib(Code Generation Library)**:当原对象没有实现接口或者为了性能考虑时,可以使用CGLib库来生成代理对象。CGLib是基于字节码操作的库,能够动态地生成一个子类,然后通过子类实现对原对象的代理。 - *...

    动态代理原理实例Demo

    5. **对比CGLIB** - 虽然JDK动态代理方便易用,但它只适用于实现了接口的对象。对于没有接口或者接口过多的情况,可以使用CGLIB库,它通过字节码技术创建代理对象,不局限于接口。 6. **性能考虑** - 动态代理...

    easyExcal.rar

    这两个版本可能用于测试或对比不同版本的功能和性能。 7. **junit-4.10.jar**:JUnit是Java开发中最常用的单元测试框架,这里可能是为了在开发或测试EasyExcel的相关功能时进行自动化测试。 这些库的组合使用,...

    互联网大厂Java面试题合集

    - **Beef平台**:Beef是一个流行的XSS攻击框架,用于演示和测试XSS漏洞。 ##### 8.2.1 IP频率限制与信誉度模型 - **IP频率限制**:通过限制同一IP地址在单位时间内发起的请求次数来防止DDoS攻击。 - **IP信誉度模型...

    支持多数据库的ORM框架ef-orm.zip

    实际性能测试表明,EF的大部分操作都要快于Hiberante和MyBatis, 部分操作速度甚至数十倍于上述框架。 EF在极限插入模式下,甚至刷新了每秒10万条写入的记录。远远超过了其他框架。 一个初步的性能测试:测试代码...

    Java面试题

    Java面试题是程序员在求职过程中经常会遇到的一种考核方式,它主要测试候选人在Java编程语言方面的基础知识、编程能力、设计模式、并发处理、框架应用、数据库操作等多方面的能力。以下是一些Java面试中常见的知识点...

    java面试的一些题,下载自msdn

    1. JUnit测试:单元测试的编写与断言。 2. Maven与Gradle:构建工具的使用与项目管理。 3. Docker与Kubernetes:容器化技术及其在部署中的应用。 以上就是基于标题“java面试的一些题,下载自msdn”所涉及的主要...

    springmvc+spring+mybatis集成框架的环境搭建

    CGLib 是一个强大的高性能的代码生成库,它被 Spring 框架用来实现 AOP 功能。 **3. Log4j 日志库:** ``` &lt;groupId&gt;log4j &lt;artifactId&gt;log4j &lt;version&gt;1.2.14 &lt;scope&gt;provided ``` 日志记录工具,用于记录...

    javassist-3.15.0-GA

    9. **与反射的对比**: 相比 Java 反射,Javaassist 在运行时动态修改类的性能更好,因为它直接操作字节码,而反射则需要解析类结构。 在实际开发中,Javaassist 常常用于以下场景: - **AOP 框架**: 如 Spring AOP...

    Hibernate快速学习PPT

    2. O/R Mapping的优点包括提高开发效率、增强代码的可维护性、提升系统性能以及保持对数据库供应商的独立性。 二、Hibernate的优势: 1. 开源:Hibernate是一个开放源码的项目,允许开发者自由查看和修改其源代码。...

    SSM-Boot面试题,都是来自工作中的笔记

    - **优势分析**:使用Spring的IoC容器管理对象,可以显著减少代码量,提高可维护性和可测试性。 #### AOP底层实现机制 **AOP**(Aspect Oriented Programming,面向切面编程)是Spring框架中的一个重要特性,用于...

    JAVA,数据库面试题集锦

    6. **JAVA反射和动态代理**:了解如何在运行时获取类信息、创建对象和调用方法,以及CGLIB和Java动态代理的应用。 7. **JVM**:理解JVM的工作原理,包括类加载机制、内存模型、调优策略等。 接下来是数据库部分,...

    java面试题集大全

    - 接口与抽象类:对比两者的区别,何时选择使用接口,何时选择抽象类。 - CopyOnWriteArrayList和ConcurrentHashMap:线程安全的集合实现,适合多线程环境。 3. **多线程** - Thread类与Runnable接口:创建线程...

    JavaEE技术问题汇总.docx

    【Java深复制与浅复制】 ...以上仅是部分知识点,更多如静态代理、动态代理、CGLIB与JDK代理、静态关键字、CAS单点登录原理等未展开详述。这些知识涵盖JavaEE开发的多个方面,对于理解和优化JavaEE应用至关重要。

    hibernate基本配置及使用方法

    对比来看,使用Hibernate可以大大简化这些过程,通过配置文件和注解就能完成数据持久化,降低了代码的复杂性。 ### 五、Hibernate的一对多和多对多关系配置 1. **一对一(OneToOne)**:一个实体对应另一个实体的...

    一线互联网公司面试题目

    11. **AOP 底层实现**:AOP(面向切面编程)通常通过动态代理实现,如JDK动态代理和CGLIB,可以为多个对象动态地生成代理类。 12. **Maven指令**:maven install构建本地库,maven test执行测试,git make install...

Global site tag (gtag.js) - Google Analytics