• 【Java】Bean复制几种实现方法性能比较


    【引言】

    在项目开发过程中,会遇到将某个已有若干属性值的Bean复制给另一个具有相同属性名的Bean,除了一个一个属性去set方法之外,其实可以通过调用一些工具类下的方法直接copy,这样就避免了一个一个去set属性值,在简化了代码的基础上,也能快速地实现功能。

    而实现这种功能的工具类并不只有一种,也听同事提到过如果数据量大的话,性能上会有影响。所以在工作空闲之时,自己写了个接口,测试了一下每种方法需要花费的时间,写个博客记录下来。

    【方法】

    Apache 的BeanUtils
    Apache 的PropertyUtils
    Spring 的BeanUtils
    反射工具包ReflectASM 自定义工具类
    【测试】

    测试的场景是在我们的商品应用服务中,写了一个接口,查询商品数据比较多的一个店铺,大概8万条左右,将查出来的实体ShopGoods数据拷贝到一个数据传输实体ShopGoodsDTO,结果返回的是拷贝所花费的时间,单位为毫秒。

    下面是测试结果统计:

    实现方法 花费时间(ms)

    Apache 的BeanUtils    9431
    Apache 的PropertyUtils    8083
    Spring 的BeanUtils    4827
    反射工具包ReflectASM 自定义工具类    4777


    【代码】

    //利用反射工具包ReflectASM自定义工具类
    public class BeanUtils {
    
    private static Map<Class, MethodAccess> methodMap = new HashMap<Class, MethodAccess>();
    
    private static Map<String, Integer> methodIndexMap = new HashMap<String, Integer>();
    
    private static Map<Class, List<String>> fieldMap = new HashMap<Class, List<String>>();
    
    public static void copyProperties(Object desc, Object orgi) {
    MethodAccess descMethodAccess = methodMap.get(desc.getClass());
    if (descMethodAccess == null) {
    descMethodAccess = cache(desc);
    }
    MethodAccess orgiMethodAccess = methodMap.get(orgi.getClass());
    if (orgiMethodAccess == null) {
    orgiMethodAccess = cache(orgi);
    }
    
    List<String> fieldList = fieldMap.get(orgi.getClass());
    for (String field : fieldList) {
    String getKey = orgi.getClass().getName() + "." + "get" + field;
    String setkey = desc.getClass().getName() + "." + "set" + field;
    Integer setIndex = methodIndexMap.get(setkey);
    if (setIndex != null) {
    int getIndex = methodIndexMap.get(getKey);
    // 参数一需要反射的对象
    // 参数二class.getDeclaredMethods 对应方法的index
    // 参数对三象集合
    descMethodAccess.invoke(desc, setIndex.intValue(),
    orgiMethodAccess.invoke(orgi, getIndex));
    }
    }
    }
    
    // 单例模式
    private static MethodAccess cache(Object orgi) {
    synchronized (orgi.getClass()) {
    MethodAccess methodAccess = MethodAccess.get(orgi.getClass());
    Field[] fields = orgi.getClass().getDeclaredFields();
    List<String> fieldList = new ArrayList<String>(fields.length);
    for (Field field : fields) {
    if (Modifier.isPrivate(field.getModifiers())
    && !Modifier.isStatic(field.getModifiers())) { // 是否是私有的,是否是静态的
    // 非公共私有变量
    String fieldName = StringUtils.capitalize(field.getName()); // 获取属性名称
    int getIndex = methodAccess.getIndex("get" + fieldName); // 获取get方法的下标
    int setIndex = methodAccess.getIndex("set" + fieldName); // 获取set方法的下标
    methodIndexMap.put(orgi.getClass().getName() + "." + "get"
    + fieldName, getIndex); // 将类名get方法名,方法下标注册到map中
    methodIndexMap.put(orgi.getClass().getName() + "." + "set"
    + fieldName, setIndex); // 将类名set方法名,方法下标注册到map中
    fieldList.add(fieldName); // 将属性名称放入集合里
    }
    }
    fieldMap.put(orgi.getClass(), fieldList); // 将类名,属性名称注册到map中
    methodMap.put(orgi.getClass(), methodAccess);
    return methodAccess;
    }
    }
    
    }
    /**
    * 测试方法:将查出的商品实体数据利用不同工具包下的方法拷贝至一个新的传输实体
    * 商品数据量:八万左右
    */
    public long costSeconds() {
    List<ShopGoodsDTO> shopGoodsDTOList=new ArrayList<>();
    ShopGoodsExample shopGoodsExample = new ShopGoodsExample();
    shopGoodsExample.createCriteria().andStoreIdEqualTo(743);
    // 查询到的商品数据
    List<ShopGoods> shopGoodsList = shopGoodsMapper.selectByExample(shopGoodsExample);
    long costSeconds=0L;
    if(shopGoodsList!=null && shopGoodsList.size()>0){
    long startTime=System.currentTimeMillis();
    for (ShopGoods shopGoods:shopGoodsList) {
    ShopGoodsDTO shopGoodsDTO = new ShopGoodsDTO();
    BeanUtils.copyProperties(shopGoodsDTO,shopGoods);
    //org.springframework.beans.BeanUtils.copyProperties(shopGoods,shopGoodsDTO);
    //BeanUtils.copyProperties(shopGoodsDTO,shopGoods);
    // try {
    // PropertyUtils.copyProperties(shopGoodsDTO,shopGoods);
    // } catch (NoSuchMethodException e) {
    // e.printStackTrace();
    // }
    System.out.println(new Gson().toJson(shopGoodsDTO));
    shopGoodsDTOList.add(shopGoodsDTO);
    }
    long endTime=System.currentTimeMillis();
    costSeconds=endTime-startTime;
    }
    return costSeconds;
    }


    【总结】

    通过以上测试可以看出,Apache下的工具包下的方法性能较差,和Spring工具包下的方法及利用反射工具包ReflectASM自定义工具类的方法相比,时间上是需要多花一倍的。

    而Spring工具包下的方法与利用反射工具包ReflectASM自定义工具类的方法相比,时间上是差不多的。

    所以个人感觉,我们需要实现此类功能的时候,直接利用Spring BeanUtils工具包下的copyProperties方法即可。需要注意的是Spring BeanUtils下的方法参数与Apache BeanUtils下的方法参数是相反的,在使用时不要将源实体与目标实体弄混了。
    ————————————————
    版权声明:本文为CSDN博主「好好生活_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/u013034223/java/article/details/88063629

  • 相关阅读:
    寒假作业1
    秋季学习总结
    记叙在人生路上对你影响最大的三位老师
    2019年春季学期第二周作业
    币值转换
    第九周作业
    第八周作业
    第七周作业
    第六周作业
    第五周作业
  • 原文地址:https://www.cnblogs.com/weixupeng/p/13324568.html
Copyright © 2020-2023  润新知