开发中经常用到bean的复制,常用的有Apache BeanUtils、PropertyUtils,Spring BeanUtils,Cglib BeanCopier和直接set,下面对这几种简单进行性能测试
FromBean ToBean
@Data
public class FromBean {
private String name;
private int age;
private String address;
private String idNo;
private BigDecimal money;
}
@Data
public class ToBean extends FromBean {
}
BenchmarkTest
public class BenchmarkTest {
private int count;
public BenchmarkTest(int count) {
this.count = count;
System.out.println("性能测试" + this.count + "==================");
}
public void benchmark(MethodCallBack m, FromBean frombean) {
try {
long begin = System.currentTimeMillis();
ToBean tobean = null;
for (int i = 0; i < count; i++) {
tobean = m.callMethod(frombean);
}
System.out.println(String.format("%-60s 耗时:%sms", m.getMethodName(),
System.currentTimeMillis() - begin));
} catch (Exception e) {
e.printStackTrace();
}
}
}
MethodCallBack
public interface MethodCallBack {
String getMethodName();
ToBean callMethod(FromBean frombean) throws Exception;
}
TestMain
public class TestMain {
public static void main(String[] args) {
FromBean fb = new FromBean();
fb.setAddress("北京市朝阳区大屯路");
fb.setAge(20);
fb.setMoney(new BigDecimal(30000.111));
fb.setIdNo("110330219879208733");
fb.setName("测试");
MethodCallBack beanutilCB = new MethodCallBack() {
@Override
public String getMethodName() {
return "org.apache.commons.beanutils.BeanUtils.copyProperties";
}
@Override
public ToBean callMethod(FromBean frombean) throws Exception {
ToBean toBean = new ToBean();
BeanUtils.copyProperties(toBean, frombean);
return toBean;
}
};
MethodCallBack propertyCB = new MethodCallBack() {
@Override
public String getMethodName() {
return "org.apache.commons.beanutils.PropertyUtils.copyProperties";
}
@Override
public ToBean callMethod(FromBean frombean) throws Exception {
ToBean toBean = new ToBean();
PropertyUtils.copyProperties(toBean, frombean);
return toBean;
}
};
MethodCallBack springCB = new MethodCallBack() {
@Override
public String getMethodName() {
return "org.springframework.beans.BeanUtils.copyProperties";
}
@Override
public ToBean callMethod(FromBean frombean) throws Exception {
ToBean toBean = new ToBean();
org.springframework.beans.BeanUtils.copyProperties(frombean,
toBean);
return toBean;
}
};
MethodCallBack cglibCB = new MethodCallBack() {
BeanCopier bc = BeanCopier.create(FromBean.class, ToBean.class,
false);
@Override
public String getMethodName() {
return "org.springframework.cglib.beans.BeanCopier.create";
}
@Override
public ToBean callMethod(FromBean frombean) throws Exception {
ToBean toBean = new ToBean();
bc.copy(frombean, toBean, null);
return toBean;
}
};
MethodCallBack setCB = new MethodCallBack() {
@Override
public String getMethodName() {
return "set method";
}
@Override
public ToBean callMethod(FromBean frombean) throws Exception {
ToBean toBean = new ToBean();
toBean.setAddress(frombean.getAddress());
toBean.setAge(frombean.getAge());
toBean.setIdNo(frombean.getIdNo());
toBean.setMoney(frombean.getMoney());
toBean.setName(frombean.getName());
return toBean;
}
};
// 数量较少的时候,测试性能
BenchmarkTest bt = new BenchmarkTest(10);
bt.benchmark(beanutilCB, fb);
bt.benchmark(propertyCB, fb);
bt.benchmark(springCB, fb);
bt.benchmark(cglibCB, fb);
bt.benchmark(setCB, fb);
// 测试一千次性能测试
BenchmarkTest bt1000 = new BenchmarkTest(1000);
bt1000.benchmark(beanutilCB, fb);
bt1000.benchmark(propertyCB, fb);
bt1000.benchmark(springCB, fb);
bt1000.benchmark(cglibCB, fb);
bt1000.benchmark(setCB, fb);
// 测试一万次性能测试
BenchmarkTest bt10000 = new BenchmarkTest(10000);
bt10000.benchmark(beanutilCB, fb);
bt10000.benchmark(propertyCB, fb);
bt10000.benchmark(springCB, fb);
bt10000.benchmark(cglibCB, fb);
bt10000.benchmark(setCB, fb);
// 担心因为顺序问题影响测试结果
BenchmarkTest bt1000R = new BenchmarkTest(10000);
bt1000R.benchmark(setCB, fb);
bt1000R.benchmark(cglibCB, fb);
bt1000R.benchmark(springCB, fb);
bt1000R.benchmark(propertyCB, fb);
bt1000R.benchmark(beanutilCB, fb);
}
}
测试结果:
第一次:
性能测试10==================
org.apache.commons.beanutils.BeanUtils.copyProperties 耗时:791ms
org.apache.commons.beanutils.PropertyUtils.copyProperties 耗时:6ms
org.springframework.beans.BeanUtils.copyProperties 耗时:43ms
org.springframework.cglib.beans.BeanCopier.create 耗时:0ms
set method 耗时:0ms
性能测试1000==================
org.apache.commons.beanutils.BeanUtils.copyProperties 耗时:79ms
org.apache.commons.beanutils.PropertyUtils.copyProperties 耗时:21ms
org.springframework.beans.BeanUtils.copyProperties 耗时:17ms
org.springframework.cglib.beans.BeanCopier.create 耗时:1ms
set method 耗时:0ms
性能测试10000==================
org.apache.commons.beanutils.BeanUtils.copyProperties 耗时:291ms
org.apache.commons.beanutils.PropertyUtils.copyProperties 耗时:104ms
org.springframework.beans.BeanUtils.copyProperties 耗时:43ms
org.springframework.cglib.beans.BeanCopier.create 耗时:1ms
set method 耗时:1ms
性能测试10000==================
set method 耗时:0ms
org.springframework.cglib.beans.BeanCopier.create 耗时:0ms
org.springframework.beans.BeanUtils.copyProperties 耗时:27ms
org.apache.commons.beanutils.PropertyUtils.copyProperties 耗时:56ms
org.apache.commons.beanutils.BeanUtils.copyProperties 耗时:94ms
第二次:
性能测试10==================
org.apache.commons.beanutils.BeanUtils.copyProperties 耗时:731ms
org.apache.commons.beanutils.PropertyUtils.copyProperties 耗时:5ms
org.springframework.beans.BeanUtils.copyProperties 耗时:58ms
org.springframework.cglib.beans.BeanCopier.create 耗时:0ms
set method 耗时:0ms
性能测试1000==================
org.apache.commons.beanutils.BeanUtils.copyProperties 耗时:91ms
org.apache.commons.beanutils.PropertyUtils.copyProperties 耗时:17ms
org.springframework.beans.BeanUtils.copyProperties 耗时:30ms
org.springframework.cglib.beans.BeanCopier.create 耗时:1ms
set method 耗时:0ms
性能测试10000==================
org.apache.commons.beanutils.BeanUtils.copyProperties 耗时:261ms
org.apache.commons.beanutils.PropertyUtils.copyProperties 耗时:87ms
org.springframework.beans.BeanUtils.copyProperties 耗时:60ms
org.springframework.cglib.beans.BeanCopier.create 耗时:2ms
set method 耗时:0ms
性能测试10000==================
set method 耗时:1ms
org.springframework.cglib.beans.BeanCopier.create 耗时:1ms
org.springframework.beans.BeanUtils.copyProperties 耗时:33ms
org.apache.commons.beanutils.PropertyUtils.copyProperties 耗时:43ms
org.apache.commons.beanutils.BeanUtils.copyProperties 耗时:80ms
第三次:
性能测试10==================
org.apache.commons.beanutils.BeanUtils.copyProperties 耗时:710ms
org.apache.commons.beanutils.PropertyUtils.copyProperties 耗时:5ms
org.springframework.beans.BeanUtils.copyProperties 耗时:72ms
org.springframework.cglib.beans.BeanCopier.create 耗时:0ms
set method 耗时:0ms
性能测试1000==================
org.apache.commons.beanutils.BeanUtils.copyProperties 耗时:98ms
org.apache.commons.beanutils.PropertyUtils.copyProperties 耗时:96ms
org.springframework.beans.BeanUtils.copyProperties 耗时:13ms
org.springframework.cglib.beans.BeanCopier.create 耗时:1ms
set method 耗时:1ms
性能测试10000==================
org.apache.commons.beanutils.BeanUtils.copyProperties 耗时:268ms
org.apache.commons.beanutils.PropertyUtils.copyProperties 耗时:80ms
org.springframework.beans.BeanUtils.copyProperties 耗时:73ms
org.springframework.cglib.beans.BeanCopier.create 耗时:1ms
set method 耗时:0ms
性能测试10000==================
set method 耗时:0ms
org.springframework.cglib.beans.BeanCopier.create 耗时:1ms
org.springframework.beans.BeanUtils.copyProperties 耗时:56ms
org.apache.commons.beanutils.PropertyUtils.copyProperties 耗时:43ms
org.apache.commons.beanutils.BeanUtils.copyProperties 耗时:99ms
结论:
Apache BeanUtils 性能最差
Apache PropertyUtils 基本是线性增长
Spring BeanUtils 不稳定
Cglib和直接set性能最好
原因分析:
Apache BeanUtils、PropertyUtils、Spring BeanUtils采用反射
Cglib采用动态代理