今天开发中遇到一个小问题。
因为前期沟通不到位。有同学把一个后台接口(用于获取ES中的商品数据)的id相关字段,都设置成了Interge。而我们公司ID的要求是Long。
这导致数据后期维护十分不方便。还容易出错,举个例子
因为泛型擦除所以并不会报错且iidMap真实返回类型是Map
因为是Dubbo服务已经暴露出去。。。不太好收口。后期会废弃使用新的接口。临时的方案,准备用代理层,进行对象的拷贝。
那么我们问题就变成如下2个问题
1:如何选择JAVA Bean的Copy方式
2:Interge要能自动转化为Long
先把备的拷贝思路罗列出来
1. 手工编码
2. 动态代理
3. Spring反射
4. 序列化
有了思路,那我开搞,顺道学习和复习总结一下JAVA对象的拷贝。
其中序列化方式,在这里其实是可行的。首先后台的量级不大,操作也方便,也能进行Interge和Long的转换。相对的序列化有明显的性能瓶颈,在大量操作时性能下降的特别快。
抱着好奇,我们一并探究并验证下手工编码,动态代理,Spring反射具体性能如何?能否转换Interge和Long?
有了相关的思路,网上也找了一下文章,自己动手实现一下
具体代码基本结构参考三石雨的文章大家可以看看
5中方式的效率如图所示。
效率来说:
手写 > 动态代理 > 反射
1. ManualCopy: 手动编写,效率最高,能类型转换,代码量多
2. Cglib:动态代理,效率高,不能进行类型转换
3. Apache Bean Utils , 反射,比较耗时,能进行类型转换
4. Spring Bean Utils :反射中等耗时,不能进行类型住哪换
5. Apache Property Utils : 反射 类型不同,直接报错。
来看看代码结构。
cglib
cglib
3.2.2
org.springframework
spring-core
5.2.5.RELEASE
commons-beanutils
commons-beanutils
1.9.2
org.springframework
spring-beans
5.2.5.RELEASE
junit
junit
SourceBean :id为Integer
package com.lctest.demo.lctrain.JavaBeanCopyTest.TO;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
import java.util.Map;
/**
* SourceBean :id为Integer
*
* @author xiwen.chen
* @since 2020-05-06
*/
@Setter
@Getter
public class SourceBean {
private Integer iid;
@JsonProperty("gmt_create")
private Integer gmtCreate;
private String name;
@JsonProperty("actor_map")
private Map<String, String> actorMap;
}
DestBean:对应Source的id 变为 Long型
package com.lctest.demo.lctrain.JavaBeanCopyTest.TO;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
import java.util.Map;
/**
* DestBean:对应Source的id 变为 Long型
*
* @author xiwen.chen
* @since 2020-05-06
*/
@Setter
@Getter
public class DestBean {
private Long iid;
@JsonProperty("gmt_create")
private Long gmtCreate;
private String name;
@JsonProperty("actor_map")
private Map<String, String> actorMap;
}
package com.lctest.demo.lctrain.JavaBeanCopyTest;
import com.lctest.demo.lctrain.JavaBeanCopyTest.TO.DestBean;
import com.lctest.demo.lctrain.JavaBeanCopyTest.TO.SourceBean;
/**
* desc
*
* @author xiwen.chen
* @since 2020-05-06
*/
public class CopyProcessor {
private int count;
public CopyProcessor(int count) {
this.count = count;
System.out.println("性能测试=======" + this.count + "===========");
}
public void process(CopyMethod methodCallBack, SourceBean sourceBean) throws Exception {
long processBegin = System.currentTimeMillis();
DestBean destBean = null;
System.out.println(methodCallBack.getMethodName() + "测试开始!");
for (int i = 0; i < count; i++) {
destBean = methodCallBack.beanCopy(sourceBean);
}
long processEnd = System.currentTimeMillis();
long timeConsuming = processEnd - processBegin;
System.out.println(methodCallBack.getMethodName() + "测试结束!共耗时" + timeConsuming + "毫秒,copy结果如下:");
System.out.println(destBean.getName());
System.out.println(destBean.getIid());
System.out.println(destBean.getActorMap());
System.out.println(destBean.getGmtCreate());
System.out.println("=============================================");
}
}
package com.lctest.demo.lctrain.JavaBeanCopyTest;
import com.lctest.demo.lctrain.JavaBeanCopyTest.TO.SourceBean;
import com.lctest.demo.lctrain.JavaBeanCopyTest.copymethod.ApacheBeanUtilsCopy;
import com.lctest.demo.lctrain.JavaBeanCopyTest.copymethod.ApachePropertyUtilsCopy;
import com.lctest.demo.lctrain.JavaBeanCopyTest.copymethod.CglibCopy;
import com.lctest.demo.lctrain.JavaBeanCopyTest.copymethod.ManualCopy;
import com.lctest.demo.lctrain.JavaBeanCopyTest.copymethod.SpringBeanUtilsCopy;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
/**
* desc
*
* @author xiwen.chen
* @since 2020-05-06
*/
public class PerformanceTest {
private SourceBean sourceBean = null;
private ManualCopy manualCopy = null;
private CglibCopy cglibCopy = null;
private ApacheBeanUtilsCopy apacheBeanUtilsCopy = null;
private ApachePropertyUtilsCopy apachePropertyUtilsCopy = null;
private SpringBeanUtilsCopy springBeanUtilsCopy = null;
@Before
public void init() {
sourceBean = new SourceBean();
sourceBean.setIid(445939013);
sourceBean.setGmtCreate(1588694400);
sourceBean.setName("xiwen copy bean test");
Map<String, String> actorName = new HashMap<>();
actorName.put("name1", "惜文");
actorName.put("name2", "荣荣");
actorName.put("name3", "新新");
sourceBean.setActorMap(actorName);
manualCopy = new ManualCopy();
cglibCopy = new CglibCopy();
apacheBeanUtilsCopy = new ApacheBeanUtilsCopy();
apachePropertyUtilsCopy = new ApachePropertyUtilsCopy();
springBeanUtilsCopy = new SpringBeanUtilsCopy();
}
@Test
public void performTest10000() throws Exception {
CopyProcessor copyProcessor = new CopyProcessor(10000);
copyProcessor.process(apacheBeanUtilsCopy, sourceBean);
copyProcessor.process(manualCopy, sourceBean);
copyProcessor.process(cglibCopy, sourceBean);
copyProcessor.process(springBeanUtilsCopy, sourceBean);
copyProcessor.process(apachePropertyUtilsCopy, sourceBean);
}
}
接口
package com.lctest.demo.lctrain.JavaBeanCopyTest;
import com.lctest.demo.lctrain.JavaBeanCopyTest.TO.DestBean;
import com.lctest.demo.lctrain.JavaBeanCopyTest.TO.SourceBean;
/**
* desc
*
* @author xiwen.chen
* @since 2020-05-06
*/
public interface CopyMethod {
public String getMethodName();
public DestBean beanCopy(SourceBean sourceBean) throws Exception;
}
实现类
public class ManualCopy implements CopyMethod {
@Override
public String getMethodName() {
return "manual copy";
}
@Override
public DestBean beanCopy(SourceBean sourceBean) throws Exception {
DestBean destBean = new DestBean();
destBean.setActorMap(sourceBean.getActorMap());
destBean.setGmtCreate(sourceBean.getGmtCreate().longValue());
destBean.setIid(sourceBean.getIid().longValue());
destBean.setName(sourceBean.getName());
return destBean;
}
}
public class SpringBeanUtilsCopy implements CopyMethod {
@Override
public String getMethodName() {
return "Spring Bean Utils";
}
@Override
public DestBean beanCopy(SourceBean sourceBean) throws Exception {
DestBean destBean = new DestBean();
BeanUtils.copyProperties(sourceBean, destBean);
return destBean;
}
}
public class CglibCopy implements CopyMethod {
private BeanCopier beanCopier = BeanCopier.create(SourceBean.class, DestBean.class, false);
@Override
public String getMethodName() {
return "Cglib BeanCopier";
}
@Override
public DestBean beanCopy(SourceBean sourceBean) throws Exception {
DestBean destBean = new DestBean();
beanCopier.copy(sourceBean, destBean, null);
return destBean;
}
}
public class ApachePropertyUtilsCopy implements CopyMethod {
@Override
public String getMethodName() {
return "Apache Property Utils";
}
@Override
public DestBean beanCopy(SourceBean sourceBean) throws Exception {
DestBean destBean = new DestBean();
PropertyUtils.copyProperties(destBean, sourceBean);
return destBean;
}
}
public class ApacheBeanUtilsCopy implements CopyMethod {
@Override
public String getMethodName() {
return "Apache Bean Utils";
}
@Override
public DestBean beanCopy(SourceBean sourceBean) throws Exception {
DestBean destBean = new DestBean();
BeanUtils.copyProperties(destBean, sourceBean);
return destBean;
}
}
好了,得到结论,那我要开始手写了转换了。。。(:з」∠)~~