Bean拷貝工具類性能比較
引言
幾年前做過一個項目,接入新的api接口。爲了和api實現解耦,決定將api返回的實體類在本地也建一個。這樣做有兩個好處
- 可以在api變更字段的時候保持應用穩定性
- 可以對返回的實體的屬性做處理,以提高可讀性。例如接口返回long類型的時間戳,則將該字段在本地實體類中對應字段設置爲date類型方便使用。
大致是這樣的一個應用場景。當時剛畢業,充斥的都是A.setName(B.getName)這種類型的代碼。當字段非常多的時候看起來非常臃腫,最重要的給人感覺不優雅。
再給我一次機會
如果上天再給我一次機會,我會跟他說,我有四種工具類可以優雅的解決這個問題。
分別是
- org.apache.commons.beanutils.PropertyUtils.copyProperties
- org.apache.commons.beanutils.BeanUtils.copyProperties
- org.springframework.beans.BeanUtils.copyProperties
- net.sf.cglib.beans.BeanCopier
Talk is cheap, show me code
定義SourceBean
package com.zhaoyangwoo.model;
/**
- Created by john on 16/7/28.
*/
public class SourceBean {
<span class="hljs-keyword">private</span> Integer age;
<span class="hljs-keyword">private</span> String title;
<span class="hljs-keyword">private</span> String source;
<span class="hljs-keyword">private</span> Boolean eat;
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">SourceBean</span><span class="hljs-params">(Integer i, String name, Boolean eat, String source)</span> </span>{
<span class="hljs-keyword">this</span>.age = i;
<span class="hljs-keyword">this</span>.title = name;
<span class="hljs-keyword">this</span>.eat = eat;
<span class="hljs-keyword">this</span>.source = source;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setAge</span><span class="hljs-params">(Integer age)</span> </span>{
<span class="hljs-keyword">this</span>.age = age;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getTitle</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">return</span> title;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setTitle</span><span class="hljs-params">(String title)</span> </span>{
<span class="hljs-keyword">this</span>.title = title;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> Boolean <span class="hljs-title">getEat</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">return</span> eat;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setEat</span><span class="hljs-params">(Boolean eat)</span> </span>{
<span class="hljs-keyword">this</span>.eat = eat;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getSource</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">return</span> source;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setSource</span><span class="hljs-params">(String source)</span> </span>{
<span class="hljs-keyword">this</span>.source = source;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> Integer <span class="hljs-title">getAge</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">return</span> age;
}
}
定義DesBean
package com.zhaoyangwoo.model;
/**
- Created by john on 16/7/28.
*/
public class DstBean {
<span class="hljs-keyword">private</span> Integer age;
<span class="hljs-keyword">private</span> String title;
<span class="hljs-keyword">private</span> Boolean eat;
<span class="hljs-keyword">private</span> String self;
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getSelf</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">return</span> self;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setSelf</span><span class="hljs-params">(String self)</span> </span>{
<span class="hljs-keyword">this</span>.self = self;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> Integer <span class="hljs-title">getAge</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">return</span> age;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setAge</span><span class="hljs-params">(Integer age)</span> </span>{
<span class="hljs-keyword">this</span>.age = age;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getTitle</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">return</span> title;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setTitle</span><span class="hljs-params">(String title)</span> </span>{
<span class="hljs-keyword">this</span>.title = title;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> Boolean <span class="hljs-title">getEat</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">return</span> eat;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setEat</span><span class="hljs-params">(Boolean eat)</span> </span>{
<span class="hljs-keyword">this</span>.eat = eat;
}
}
測試函數
package com.zhaoyangwoo.biz;
import com.zhaoyangwoo.model.DstBean;
import com.zhaoyangwoo.model.SourceBean;
import net.sf.cglib.beans.BeanCopier;
/**
- Created by john on 16/7/28.
*/
public class BeanCopyMain {
private static BeanCopier beanCopier = BeanCopier.create(SourceBean.class, DstBean.class, false);
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>{
Integer[] times = {<span class="hljs-number">10000</span>, <span class="hljs-number">1000</span>, <span class="hljs-number">10</span>};
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < times.length; i++) {
Integer time = times[i];
doCopy(time, (x, y) -> org.apache.commons.beanutils.PropertyUtils.copyProperties(y, x), <span class="hljs-string">"org.apache.commons.beanutils.PropertyUtils.copyProperties"</span>);
doCopy(time, (x, y) -> org.apache.commons.beanutils.BeanUtils.copyProperties(y, x), <span class="hljs-string">"org.apache.commons.beanutils.BeanUtils.copyProperties"</span>);
doCopy(time, (x, y) -> org.springframework.beans.BeanUtils.copyProperties(y, x), <span class="hljs-string">"org.springframework.beans.BeanUtils.copyProperties"</span>);
doCopy(time, (x, y) -> beanCopier.copy(x, y, <span class="hljs-keyword">null</span>), <span class="hljs-string">"net.sf.cglib.beans.BeanCopier.copy"</span>);
doCopy(time, (x, y) -> {
y.setEat(x.getEat());
y.setTitle(x.getTitle());
y.setAge(x.getAge());
}, <span class="hljs-string">"getter/setter"</span>);
}
}
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doCopy</span><span class="hljs-params">(Integer time, BeanCopy beanCopy, String type)</span> <span class="hljs-keyword">throws</span> Exception </span>{
<span class="hljs-keyword">long</span> startTime = System.currentTimeMillis();
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j < time; j++) {
SourceBean sourceBean = <span class="hljs-keyword">new</span> SourceBean(j, <span class="hljs-string">"source"</span> + j, <span class="hljs-keyword">false</span>, <span class="hljs-string">"abc"</span>);
DstBean dstBean = <span class="hljs-keyword">new</span> DstBean();
beanCopy.copy(sourceBean, dstBean);
}
System.out.printf(<span class="hljs-string">"執行%d次用時%dms---------%s%n"</span>, time, System.currentTimeMillis() - startTime, type);
}
<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">BeanCopy</span> </span>{
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">copy</span><span class="hljs-params">(SourceBean from, DstBean to)</span> <span class="hljs-keyword">throws</span> Exception</span>;
}
}
執行結果如下
結論
根據上面的運行結果,我們可以得出以下結論
- property少,寫起來也不麻煩,就直接用傳統的getter/setter,性能最好
- property多,轉換不頻繁,那就省點事吧,使用org.apache.commons.beanutils.BeanUtils.copyProperties
- property多,轉換很頻繁,爲性能考慮,使用net.sf.cglib.beans.BeanCopier.BeanCopier,性能近乎getter/setter。但是BeanCopier的創建時消耗較大,所以不要頻繁創建該實體,最好的處理方式是靜態化或者緩存起來。