前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你还在用BeanUtils做对象拷贝吗?

你还在用BeanUtils做对象拷贝吗?

作者头像
用户9927510
发布2022-07-29 08:48:56
2490
发布2022-07-29 08:48:56
举报
文章被收录于专栏:六脉神剑的程序人生

前言

文本已收录至我的GitHub仓库,欢迎Star:https://github.com/bin392328206/six-finger 种一棵树最好的时间是十年前,其次是现在

絮叨

今天看到的一篇文章,还不错,科普性的,推荐给大家

前言

最近开始负责一个数据量比较大的业务模块,要求把相关数据全部查出来,不分页,要组树结构,数据从dao层到service由entity对象到Vo对象给前端展示。那么就涉及到对象拷贝,开始的时候用的Spring的BeanUtils做对象转换,并没有什么问题,后来到了测试那里,加大数据量,发现接口越来越慢,开始以为数据库查询问题,把sql搬到数据库运行,发现并不慢,因为关键字段基本都走了索引,不会很慢,后来一步一步找,发现是BeanUtils耗时引起的,然后就有了下面的关于三种对象拷贝方式的实践

实践:Apache的BeanUtils、Spring的BeanUtils、Mapstruct

这里可能很多小伙伴只用过Spring的BeanUtils,其余的两种没用过,不过没关系,接下来来个简单的测试

引入maven依赖,为了测试方便这里直接创建的SpringBoot项目,用的junit测试

类结构

4个简单类

代码语言:javascript
复制
/**
 * @description user 实体
 * @author Wanm
 * @date 2020/7/8 21:37
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {

    private String id;

    private String name;

    private Integer age;

    private String address;

    private String sex;

}

/**
 * @description userVo
 * @author Wanm
 * @date 2020/7/8 21:37
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserVo {

    private String id;

    private String name;

    private Integer age;

    private String address;

    private String sex;

}


/**
 * @description UserTransfer
 * @author Wanm
 * @date 2020/7/8 21:37
 */
@Mapper
public interface UserTransfer {

    /**
     * entity转vo
     * @param user
     * @return
     */
    List<UserVo> entityToVo(List<User> user);
}


/**
 * 测试类
 */
@SpringBootTest
class MapstructApplicationTests {


    @Test
    void contextLoads() {
        //这里拿100w数据做数据初始化
        List<User> userList = new ArrayList<User>();
        for (int i = 0; i < 1000000; i++) {
            User user = new User(UUID.randomUUID().toString(),UUID.randomUUID().toString(),i,UUID.randomUUID().toString(),UUID.randomUUID().toString());
            userList.add(user);
        }
        System.out.println(userList.get(0));
        System.out.println("开始拷贝---------------------------------------");
        testBeanUtils(userList);
        testSpringBeanUtils(userList);
        testMapStruct(userList);
    }

    /**
     *  Apache的BeanUtils
     * @param userList
     */
    public static void testBeanUtils(List<User> userList){
        long start = System.currentTimeMillis();
        List<UserVo> userVos = new ArrayList<>();
        userList.forEach(item->{
            UserVo userVo  = new UserVo();
            try {
                BeanUtils.copyProperties(userVo,item);
                userVos.add(userVo);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        long end = System.currentTimeMillis();
        System.out.println(userVos.get(0));
        System.out.println("集合大小参数验证"+userVos.size()+"Apache的BeanUtils耗时:"+(end-start)+"ms");
    }

    /**
     * Spring的BeanUtils
     * @param userList
     */
    public static void testSpringBeanUtils(List<User> userList){
        long start = System.currentTimeMillis();
        List<UserVo> userVos = new ArrayList<>();
        userList.forEach(item->{
            UserVo userVo  = new UserVo();
            try {
                org.springframework.beans.BeanUtils.copyProperties(item,userVo);
                userVos.add(userVo);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        long end = System.currentTimeMillis();
        System.out.println(userVos.get(0));
        System.out.println("集合大小参数验证"+userVos.size()+"Spring的BeanUtils耗时:"+(end-start)+"ms");
    }

    /**
     * mapStruct拷贝
     * @param userList
     */
    public  void testMapStruct(List<User> userList){
        long start = System.currentTimeMillis();
        List<UserVo> userVos = Mappers.getMapper(UserTransfer.class).entityToVo(userList);
        long end = System.currentTimeMillis();
        System.out.println(userVos.get(0));
        System.out.println("集合大小参数验证"+userVos.size()+"mapStruct耗时:"+(end-start)+"ms");
    }

}

实际开发中vo类属性字段会比实体类少很多。这里只做测试,下面看测试结果

有没有看到MapStruct的耗时41ms,完胜有木有,数据量越大越能看到差异,下图是针对不同数据量的耗时做具体分析:

由此可以看出数据量越大MapStruct>Spring>Apache,这个性能优势越来越明显,日常开发中对象拷贝只是代码中的一小部分逻辑,如果数据量大的话还是建议大家使用MapStruct的方式,提高接口的性能。数据量不大的话Spring的BeanUtils也行,还是看实际业务场景!!!

MapStruct快的原因

MapStruct使用注解处理器生成实现类,实现类内部是原生的new对象,然后SetXxx/getXxx方式赋值进行数据拷贝的,类似lombok,看实现类的.class

代码语言:javascript
复制
public class UserTransferImpl implements UserTransfer {
    public UserTransferImpl() {
    }

    public List<UserVo> entityToVo(List<User> user) {
        if (user == null) {
            return null;
        } else {
            List<UserVo> list = new ArrayList(user.size());
            Iterator var3 = user.iterator();

            while(var3.hasNext()) {
                User user1 = (User)var3.next();
                list.add(this.userToUserVo(user1));
            }

            return list;
        }
    }

    protected UserVo userToUserVo(User user) {
        if (user == null) {
            return null;
        } else {
            UserVo userVo = new UserVo();
            userVo.setId(user.getId());
            userVo.setName(user.getName());
            userVo.setAge(user.getAge());
            userVo.setAddress(user.getAddress());
            userVo.setSex(user.getSex());
            return userVo;
        }
    }
}

Spring和Apache的BeanUtils则是用到了反射机制,内部实现也是有区别的,特别校验这块,至于他们之间的详细区别,交给小伙伴们自己去探寻啦~

结尾

总结:通过这次简单的测试,掌握了三种拷贝方式的实现方式和性能差异,不过使这块还是建议小伙伴们根据实际场景使用,MapStruct的性能确实好,当是需要引入第三方依赖,如果数据量这块不大Spring自带的BeanUtils够用。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-07-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 六脉神剑的程序人生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
    • 絮叨
      • 前言
        • 实践:Apache的BeanUtils、Spring的BeanUtils、Mapstruct
      • MapStruct快的原因
        • 结尾
        相关产品与服务
        数据库
        云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档