背景:
继上一篇文章 cglib源码学习交流
很多同学提出,因中文文档缺乏,导致对文章中的介绍看的不是很明白,更多的只是想了解具体的使用即可。所以趁势写了这篇博文,主要是将cglib中的几个工具类和常用的Reflect ,BeanUtils做一个对比,顺便也介绍一下cglib的相关用法,一举两得,望大家多多支持。
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个属性。
定义一个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回收 }
说明:
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(); }
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; }
测试环境说明:
-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测试 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);
// 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);
// 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万次
// 测试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);
// 测试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);
// 测试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);
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(); } }
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亿次