背景:
继上一篇文章 cglib源码学习交流
很多同学提出,因中文文档缺乏,导致对文章中的介绍看的不是很明白,更多的只是想了解具体的使用即可。所以趁势写了这篇博文,主要是将cglib中的几个工具类和常用的Reflect ,BeanUtils做一个对比,顺便也介绍一下cglib的相关用法,一举两得,望大家多多支持。
正题:
1. 首先定义一份Pojo Bean ,后续的测试主要围绕这个进行。
public static class CopyBean {
private int intValue;
private boolean boolValue;
private float floatValue;
private double doubleValue;
private long longValue;
private char charValue;
private byte byteValue;
private short shortValue;
private Integer integerValue;
private Boolean boolObjValue;
private Float floatObjValue;
private Double doubleObjValue;
private Long longObjValue;
private Short shortObjValue;
private Byte byteObjValue;
private BigInteger bigIntegerValue;
private BigDecimal bigDecimalValue;
private String stringValue;
......// 一堆的setter/getter方法
}
说明: 该copyBean基本包含了java的所有原型对象,基本对象,和常用的BigDecimal,BigInteger,总共17个属性。
2. 定义测试模板 (模板模式)
定义一个TestCallback接口。
interface TestCallback {
String getName();
CglibPerformanceTest.CopyBean call(CglibPerformanceTest.CopyBean source);
}
定义测试的模板方法
private static final DecimalFormat integerFormat = new DecimalFormat("#,###");
public static void testTemplate(TestCallback callback, CopyBean source, int count) {
int warmup = 10;
// 先进行预热,加载一些类,避免影响测试
for (int i = 0; i < warmup; i++) {
callback.call(source);
}
restoreJvm(); // 进行GC回收
// 进行测试
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
callback.call(source);
}
long nscost = (System.nanoTime() - start);
System.out.println(callback.getName() + " total cost=" + integerFormat.format(nscost) + "ns , each cost="
+ nscost / count + "ns");
restoreJvm();// 进行GC回收
}
说明:
- 为了测试更加精确,避免因为在一次的循环中进行处理,jvm内存,GC,Class装载对测试的影响,有一个warmup的过程,先执行少量的测试方法,这里是执行10次
- 避免jvm内存GC对测试id影响,这里有restoreJvm强制进行一次jvm GC
restoreJvm相关方法:
private static void restoreJvm() {
int maxRestoreJvmLoops = 10;
long memUsedPrev = memoryUsed();
for (int i = 0; i < maxRestoreJvmLoops; i++) {
System.runFinalization();
System.gc();
long memUsedNow = memoryUsed();
// 如果多次GC后内存稳定了,就退出
if ((ManagementFactory.getMemoryMXBean().getObjectPendingFinalizationCount() == 0)
&& (memUsedNow >= memUsedPrev)) {
break;
} else {
memUsedPrev = memUsedNow;
}
}
}
private static long memoryUsed() {
Runtime rt = Runtime.getRuntime();
return rt.totalMemory() - rt.freeMemory();
}
3. 准备原始的CopyBean数据
private static CopyBean getBean() {
CopyBean bean = new CopyBean();
bean.setIntValue(1);
bean.setBoolValue(false);
bean.setFloatValue(1.0f);
bean.setDoubleValue(1.0d);
bean.setLongValue(1l);
bean.setCharValue('a');
bean.setShortValue((short) 1);
bean.setByteValue((byte) 1);
bean.setIntegerValue(new Integer("1"));
bean.setBoolObjValue(new Boolean("false"));
bean.setFloatObjValue(new Float("1.0"));
bean.setDoubleObjValue(new Double("1.0"));
bean.setLongObjValue(new Long("1"));
bean.setShortObjValue(new Short("1"));
bean.setByteObjValue(new Byte("1"));
bean.setBigIntegerValue(new BigInteger("1"));
bean.setBigDecimalValue(new BigDecimal("1"));
bean.setStringValue("1");
return bean;
}
4. 执行相关测试
测试环境说明:
第一测试主要是一个对象的全部属性进行拷贝
- BeanCopier (cglib)
- PropertyUtils (apache-common)
- BeanUtils (apache-common)
1. BeanCopier (cglib)
-
// beanCopier测试
final BeanCopier beanCopier = BeanCopier.create(CopyBean.class, CopyBean.class, false);
final CopyBean beanCopierTarget = new CopyBean();//new一次,避免new对象产生的代价影响测试结果
testTemplate(new TestCallback() {
public String getName() {
return "BeanCopier";
}
public CopyBean call(CopyBean source) {
beanCopier.copy(source, beanCopierTarget, null);
return beanCopierTarget;
}
}, bean, testCount);
2. PropertyUtils (apache-common)
-
// PropertyUtils测试
final CopyBean propertyUtilsTarget = new CopyBean();
testTemplate(new TestCallback() {
public String getName() {
return "PropertyUtils";
}
public CopyBean call(CopyBean source) {
try {
PropertyUtils.copyProperties(propertyUtilsTarget, source);
} catch (Exception e) {
e.printStackTrace();
}
return propertyUtilsTarget;
}
}, bean, testCount);
3. BeanUtils (apache-common)
-
// BeanUtils测试
final CopyBean beanUtilsTarget = new CopyBean();
testTemplate(new TestCallback() {
public String getName() {
return "BeanUtils";
}
public CopyBean call(CopyBean source) {
try {
BeanUtils.copyProperties(beanUtilsTarget, source);
} catch (Exception e) {
e.printStackTrace();
}
return beanUtilsTarget;
}
}, bean, testCount);
测试结果:
测试次数: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
// 测试BulkBean
final BulkBean bulkBean = BulkBean.create(bean.getClass(), new String[] { getMethodName },
new String[] { setMethodName }, new Class[] { Integer.class });
final CopyBean bulkBeanTarget = new CopyBean();
testTemplate(new TestCallback() {
@Override
public String getName() {
return "BulkBean";
}
@Override
public CopyBean call(CopyBean source) {
Object[] result = bulkBean.getPropertyValues(source); // 先调用getter
bulkBean.setPropertyValues(bulkBeanTarget, result); // 再调用setter
return bulkBeanTarget;
}
}, bean, testCount);
2. BeanMap
// 测试BeanMap
final BeanMap sourceMap = BeanMap.create(bean); // 预先创建对象
final BeanMap targetMap = BeanMap.create(new CopyBean());
final CopyBean beanMapTarget = new CopyBean();
testTemplate(new TestCallback() {
@Override
public String getName() {
return "BeanMap";
}
@Override
public CopyBean call(CopyBean source) {
targetMap.setBean(beanMapTarget); // 将目标对象设置于beanMap
Object obj = sourceMap.get(fieldName);
targetMap.put(fieldName, obj);
return beanMapTarget;
}
}, bean, testCount);
3. FastClass/FastMethod
// 测试FastClass
final FastClass fastClass = FastClass.create(bean.getClass());
final FastMethod setFastMetod = fastClass.getMethod(setMethodName, new Class[] { Integer.class });
final FastMethod getFastMetod = fastClass.getMethod(getMethodName, new Class[] {});
final CopyBean fastClassTarget = new CopyBean();
testTemplate(new TestCallback() {
@Override
public String getName() {
return "FastClass";
}
@Override
public CopyBean call(CopyBean source) {
try {
Object field = getFastMetod.invoke(source, new Object[] {});// 调用get方法
setFastMetod.invoke(fastClassTarget, new Object[] { field });// 调用set方法赋值
} catch (Exception e) {
e.printStackTrace();
}
return fastClassTarget;
}
}, bean, testCount);
4. 未处理的jdk reflect
try {
// 进行method对象cache,真实应用中一般都会cache method对象
final Method getMethod = bean.getClass().getMethod(getMethodName, new Class[] {});
final Method setMethod = bean.getClass().getMethod(setMethodName, new Class[] { Integer.class });
// 测试未优化过的Reflect
final CopyBean reflect1Target = new CopyBean();
testTemplate(new TestCallback() {
@Override
public String getName() {
return "未优化过的Reflect";
}
@Override
public CopyBean call(CopyBean source) {
try {
Object field = getMethod.invoke(source, new Object[] {});
setMethod.invoke(reflect1Target, new Object[] { field });
} catch (Exception e) {
e.printStackTrace();
}
return reflect1Target;
}
}, bean, testCount);
} catch (Exception e1) {
e1.printStackTrace();
}
}
5. 处理过的jdk reflect
try {
// 进行method对象cache,真实应用中一般都会cache method对象
final Method getMethod = bean.getClass().getMethod(getMethodName, new Class[] {});
final Method setMethod = bean.getClass().getMethod(setMethodName, new Class[] { Integer.class });
// 测试优化过的Reflect
getMethod.setAccessible(true);// 设置不进行access权限检查
setMethod.setAccessible(true);// 设置不进行access权限检查
final CopyBean reflect2Target = new CopyBean();
testTemplate(new TestCallback() {
@Override
public String getName() {
return "优化过的Reflect";
}
@Override
public CopyBean call(CopyBean source) {
try {
Object field = getMethod.invoke(source, new Object[] {});
setMethod.invoke(reflect2Target, new Object[] { field });
} catch (Exception e) {
e.printStackTrace();
}
return reflect2Target;
}
}, bean, testCount);
} catch (Exception e1) {
e1.printStackTrace();
}
测试结果:
测试次数: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简介CGLIB简介CGLIB简介CGLIB简介CGLIB简介
cglib动态代理相关jar包,亲测可用cglib动态代理相关jar包,亲测可用cglib动态代理相关jar包,亲测可用
通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。 二、CGLIB原理 CGLIB原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。...
cglib
cglib.zip
开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4开发工具 cglib-3.2.4...
赠送jar包:cglib-3.1.jar; 赠送原API文档:cglib-3.1-javadoc.jar; 赠送源代码:cglib-3.1-sources.jar; 赠送Maven依赖信息文件:cglib-3.1.pom; 包含翻译后的API文档:cglib-3.1-javadoc-API文档-中文(简体)版...
cglib包及依赖汉cglib3.1和asm4.2,主要作用是用户代理,代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。...
cglib代理模式所需要的jar吧,包括cglib3.1.jar和字节码asm4.0.jar;并且经过代码测试,直接可用
cglib 的jar包,用于做动态代理的,但是版本太高不知道会不会有影响
CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。最流行的OR Mapping工具hibernate也使用CGLIB来代理单端single-ended(多对一...
CGLIB-DOC,CGLIB说明文件.
基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)基于Cglib简单实现Spring体系(Ioc+Aop+Mvc)...
在cglib需要的包,含有asm.jar asm_commons.jar asm-util.jar cglib-nodep.jar
cglib-3.2.5.jar、cglib-nodep-3.2.5.jar、cglib-RELEASE_3_2_5.tar.gz(源码)、cglib-RELEASE_3_2_5.zip(源码)
Cglib的jar文件,包含:asm.jar、asm-commons.jar、asm-tree.jar、cglib-2.2.jar 四个jar包
CGLib详细教程 CGLib详细教程 CGLib详细教程
cglib-2.2.2源码
Hibernate底层技术简介 CGLIB
里面包含完整的cglib-nodep-2.2.jar和asm-2.2.3.jar,放心下载