作为一个新员工,一个首要的工作就是阅读别人的代码,阅读代码的诸多好处就不说了,我就直奔主题,通过预读代码,发现了几种实现两个不同类型的Bean之间实现值复制的几种方式,上网查询后发现性能上会有差异,于是就萌生自己深入了解几种实现的想法。第一步就是先本着实事求是的原则去探求一下大家总结出来的性能差异是否正确。


 


       比较的是四种复制的方式,分别为Apache的BeanUtils和PropertyUtils,Spring的BeanUtils,Cglib的BeanCopier。做法是在Eclipse新建了一个Project,专门用于专门测试几种代码的性能。具体的代码如下:


       一个FromBean和一个ToBean,两个的代码基本上一样,除了类名称不一样,所以只是贴出来了一份。


       



​?​



​public​​ ​​class​​ ​​FromBean {​


​private​​ ​​String name;​


​private​​ ​​int​​ ​​age;​


​private​​ ​​String address;​


​private​​ ​​String idno;​


​private​​ ​​double​​ ​​money;​


 


​public​​ ​​double​​ ​​getMoney() {​


​return​​ ​​money;​


​}​


 


​public​​ ​​void​​ ​​setMoney(​​​​double​​ ​​money) {​


​this​​​​.money = money;​


​}​


 


​public​​ ​​String getName() {​


​return​​ ​​name;​


​}​


 


​public​​ ​​void​​ ​​setName(String name) {​


​this​​​​.name = name;​


​}​


 


​public​​ ​​int​​ ​​getAge() {​


​return​​ ​​age;​


​}​


 


​public​​ ​​void​​ ​​setAge(​​​​int​​ ​​age) {​


​this​​​​.age = age;​


​}​


 


​public​​ ​​String getAddress() {​


​return​​ ​​address;​


​}​


 


​public​​ ​​void​​ ​​setAddress(String address) {​


​this​​​​.address = address;​


​}​


 


​public​​ ​​String getIdno() {​


​return​​ ​​idno;​


​}​


 


​public​​ ​​void​​ ​​setIdno(String idno) {​


​this​​​​.idno = idno;​


​}​


 


​}​



  一个用于测试的BenchmarkTest类,为了减少重复代码,写了一个策略模式

     



Bean复制的几种框架性能比较(Apache BeanUtils、PropertyUtils,Spring BeanUtils,Cglib BeanCopier)_通用实践

public class BenchmarkTest {
private int count;
</span><span style="color: #0000ff;">public</span> BenchmarkTest(<span style="color: #0000ff;">int</span><span style="color: #000000;"> count) {
</span><span style="color: #0000ff;">this</span>.count =<span style="color: #000000;"> count;
System.out.println(</span>"性能测试" + <span style="color: #0000ff;">this</span>.count + "=================="<span style="color: #000000;">);
}

</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> benchmark(IMethodCallBack m, FromBean frombean) {
</span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
</span><span style="color: #0000ff;">long</span> begin = <span style="color: #0000ff;">new</span><span style="color: #000000;"> java.util.Date().getTime();
ToBean tobean </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">;
System.out.println(m.getMethodName() </span>+ "开始进行测试"<span style="color: #000000;">);
</span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i < count; i++<span style="color: #000000;">) {

tobean </span>=<span style="color: #000000;"> m.callMethod(frombean);

}
</span><span style="color: #0000ff;">long</span> end = <span style="color: #0000ff;">new</span><span style="color: #000000;"> java.util.Date().getTime();
System.out.println(m.getMethodName() </span>+ "耗时" + (end -<span style="color: #000000;"> begin));
System.out.println(tobean.getAddress());
System.out.println(tobean.getAge());
System.out.println(tobean.getIdno());
System.out.println(tobean.getMoney());
System.out.println(tobean.getName());
System.out.println(</span>" "<span style="color: #000000;">);
} </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) {
e.printStackTrace();
}
}


}


Bean复制的几种框架性能比较(Apache BeanUtils、PropertyUtils,Spring BeanUtils,Cglib BeanCopier)_JDK_02


 策略中使用的接口声明

 



Bean复制的几种框架性能比较(Apache BeanUtils、PropertyUtils,Spring BeanUtils,Cglib BeanCopier)_通用实践_03

public interface IMethodCallBack {
String getMethodName();

ToBean callMethod(FromBean frombean) </span><span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception;


}


Bean复制的几种框架性能比较(Apache BeanUtils、PropertyUtils,Spring BeanUtils,Cglib BeanCopier)_java经验集锦_04


 

使用的测试类



Bean复制的几种框架性能比较(Apache BeanUtils、PropertyUtils,Spring BeanUtils,Cglib BeanCopier)_JDK_05

public class TestMain {
</span><span style="color: #008000;">/**</span><span style="color: #008000;">
* </span><span style="color: #808080;">@param</span><span style="color: #008000;"> args
</span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) {
FromBean fb </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> FromBean();
fb.setAddress(</span>"北京市朝阳区大屯路"<span style="color: #000000;">);
fb.setAge(</span>20<span style="color: #000000;">);
fb.setMoney(</span>30000.111<span style="color: #000000;">);
fb.setIdno(</span>"110330219879208733"<span style="color: #000000;">);
fb.setName(</span>"测试"<span style="color: #000000;">);

IMethodCallBack beanutilCB </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> IMethodCallBack() {

@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getMethodName() {
</span><span style="color: #0000ff;">return</span> "BeanUtil.copyProperties"<span style="color: #000000;">;
}

@Override
</span><span style="color: #0000ff;">public</span> ToBean callMethod(FromBean frombean) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception {

ToBean toBean </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> ToBean();
BeanUtils.copyProperties(toBean, frombean);
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> toBean;
}
};

IMethodCallBack propertyCB </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> IMethodCallBack() {

@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getMethodName() {
</span><span style="color: #0000ff;">return</span> "PropertyUtils.copyProperties"<span style="color: #000000;">;
}

@Override
</span><span style="color: #0000ff;">public</span> ToBean callMethod(FromBean frombean) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception {
ToBean toBean </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> ToBean();
PropertyUtils.copyProperties(toBean, frombean);
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> toBean;
}
};

IMethodCallBack springCB </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> IMethodCallBack() {

@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getMethodName() {
</span><span style="color: #0000ff;">return</span> "org.springframework.beans.BeanUtils.copyProperties"<span style="color: #000000;">;
}

@Override
</span><span style="color: #0000ff;">public</span> ToBean callMethod(FromBean frombean) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception {
ToBean toBean </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> ToBean();
org.springframework.beans.BeanUtils.copyProperties(frombean,
toBean);
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> toBean;
}
};

IMethodCallBack cglibCB </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> IMethodCallBack() {
BeanCopier bc </span>= BeanCopier.create(FromBean.<span style="color: #0000ff;">class</span>, ToBean.<span style="color: #0000ff;">class</span><span style="color: #000000;">,
</span><span style="color: #0000ff;">false</span><span style="color: #000000;">);

@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getMethodName() {
</span><span style="color: #0000ff;">return</span> "BeanCopier.create"<span style="color: #000000;">;
}

@Override
</span><span style="color: #0000ff;">public</span> ToBean callMethod(FromBean frombean) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> Exception {
ToBean toBean </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> ToBean();
bc.copy(frombean, toBean, </span><span style="color: #0000ff;">null</span><span style="color: #000000;">);
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> toBean;
}
};


// 数量较少的时候,测试性能

BenchmarkTest bt = new BenchmarkTest(10);

bt.benchmark(beanutilCB, fb);

bt.benchmark(propertyCB, fb);

bt.benchmark(springCB, fb);

bt.benchmark(cglibCB, fb);


// 测试一万次性能测试

BenchmarkTest bt10000 = new BenchmarkTest(10000);

bt10000.benchmark(beanutilCB, fb);

bt10000.benchmark(propertyCB, fb);

bt10000.benchmark(springCB, fb);

bt10000.benchmark(cglibCB, fb);


// 担心因为顺序问题影响测试结果

BenchmarkTest bt1000R = new BenchmarkTest(10000);

bt1000R.benchmark(cglibCB, fb);

bt1000R.benchmark(springCB, fb);

bt1000R.benchmark(propertyCB, fb);

bt1000R.benchmark(beanutilCB, fb);

}


}


Bean复制的几种框架性能比较(Apache BeanUtils、PropertyUtils,Spring BeanUtils,Cglib BeanCopier)_通用实践_06


 

 进行了三次测试,最后的结果如下:

10次测验

第一次

第二次

第三次

平均值

每次平均值

BeanUtil.copyProperties

54

57

50

53.66667

5.366666667

PropertyUtils.copyProperties

4

4

4

4

0.4

org.springframework.beans.BeanUtils.copyProperties

12

10

11

11

1.1

BeanCopier.create

0

0

0

0

0

 

10000次测验

第一次

第二次

第三次

平均值

每次平均值

BeanUtil.copyProperties

241

222

226

229.6667

0.022966667

PropertyUtils.copyProperties

92

90

92

91.33333

0.009133333

org.springframework.beans.BeanUtils.copyProperties

29

30

32

30.33333

0.003033333

BeanCopier.create

1

1

1

1

0.1

 

10000次反转测验

第一次

第二次

第三次

平均值

每次平均值

BeanUtil.copyProperties

178

174

178

176.6667

0.017666667

PropertyUtils.copyProperties

91

87

89

89

0.0089

org.springframework.beans.BeanUtils.copyProperties

21

21

21

21

0.0021

BeanCopier.create

0

1

1

0.666667

6.66667E-05

 

      不过需要注意的是,Cglib在测试的时候,先进行了实例的缓存,这个也是他性能较好的原因之一。如果把缓存去掉的话,性能就会出现了一些的差异,但是整体的性能还是很好,不过奇怪的是10000次反而比10次少,而且后面的反转1万次反而耗时最少,进行多次测试效果也是如此。    从整体的表现来看,Cglib的BeanCopier的性能是最好的无论是数量较大的1万次的测试,还是数量较少10次,几乎都是趋近与零损耗,Spring是在次数增多的情况下,性能较好,在数据较少的时候,性能比PropertyUtils的性能差一些。PropertyUtils的性能相对稳定,表现是呈现线性增长的趋势。而Apache的BeanUtil的性能最差,无论是单次Copy还是大数量的多次Copy性能都不是很好。

 

10次

10000次

10000次反转

BeanCopier.create

41

28

10

      性能测试就到这里,数据也展示如上,后续会继续编写剩余两篇文章,这一片关注性能,后面的一篇是就每种方式的使用上的差异进行详解,最后一篇想进行探讨是什么早就了这四种方式的性能差异。