背景:
继上一篇文章 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亿次