• Java的属性拷贝工具类


    关键知识点提炼:

     

    • BeanUtils.copyProperties的使用场景:DO、DTO、VO之间的转换
    • BeanUtils.copyProperties的避坑
    • BeanUtils的替代工具类——Mapstruct

    一、BeanUtils.copyProperties的使用场景

    涉及到的DO、DTO、VO之间的转换,我们大多使用Spring框架里的BeanUtils.copyProperties来做对象转换,以下举例对比使用工具和不使用工具:

    DTO和VO的转换

    1. @Data
    2. public class OrderDTO {
    3. private long id;
    4. private Long userId;
    5. private String orderNo;
    6. private Date gmtCreated;
    7. }
    1. @Data
    2. public class OrderVO {
    3. private long id;
    4. private long userId;
    5. private String orderNo;
    6. private Date gmtCreated;
    7. }

    不使用工具转换:

    1. public static void main(String[] args) {
    2. OrderDTO orderDTO = new OrderDTO();
    3. orderDTO.setId(1L);
    4. orderDTO.setUserId(123L);
    5. orderDTO.setOrderNo("20210518000001");
    6. orderDTO.setGmtCreated(new Date());
    7. OrderVO orderVO = new OrderVO();
    8. orderVO.setId(orderDTO.getId());
    9. orderVO.setUserId(orderDTO.getUserId());
    10. orderVO.setOrderNo(orderDTO.getOrderNo());
    11. orderVO.setGmtCreated(orderDTO.getGmtCreated());
    12. }

    使用工具转换:

    1. OrderVO orderVO = new OrderVO();
    2. BeanUtils.copyProperties(orderDTO, orderVO);
    3. //使用自定义工具---如下
    4. OrderVO orderVO=BeanUtil.copyProperties(OrderVO.class, orderDTO);

    以下是自定义的一个工具类:

    1. package com.test.utils;
    2. import java.util.*
    3. import org.springframword.beans.Beanutils;
    4. import org.springframword.util.CollectionUtils;
    5. public class BeanUtil extends BeanUtils(
    6. public BeanUtil(){
    7. }
    8. public statci List Dto2List(Class destType, List orig){
    9. List dest = new ArratList();
    10. if (CollectionUtils.isEmpty(orig)){
    11. return dest;
    12. }else {
    13. Iterator it = orig.iterator();
    14. while(it.hasNext()){
    15. E e = it.next();
    16. T obj = BeanUtils.instantiateClase(destType);
    17. BeanUtils.copyProperties(e, obj);
    18. dest.add(obj);
    19. }
    20. return dest;
    21. }
    22. }
    23. public statci T copyProperties(Class destType, Object srcObject){
    24. if (srcObject == null){
    25. return null;
    26. } else {
    27. T obj = BeanUtils.instantiateClase(destType);
    28. BeanUtils.copyProperties(srcObject, obj);
    29. return obj;
    30. }
    31. }

    二、BeanUtils.copyProperties的避坑

    使用该方法是一种浅拷贝,会有坑:

    1、包装类型转基本类型问题

    例如OrderDTO的Long类型转换成OrderDO的long时,会抛java.lang.IllegalArgumentException异常

    2、空格问题

    OrderDTO的字段A带前后空格,转换成OrderDO仍然会有空格,造成脏数据。

    3、查不到饮用字段。


    三、BeanUtils的替代工具类——Mapstruct

    先上结论,Mapstruct的性能远远高于BeanUtils:

    对象转换次数

    属性个数

    BeanUtils耗时

    Mapstruct耗时

    5千万次

    6

    14秒

    1秒

    5千万次

    15

    36秒

    1秒

    5千万次

    25

    55秒

    1秒

    1、Mapstruct 依赖

    使用Mapstruct需要依赖的包如下,mapstruct、mapstruct-processor、lombok,可以去仓库中查看最新版本。

    1. org.mapstruct
    2. mapstruct
    3. 1.5.0.Final
    4. org.mapstruct
    5. mapstruct-processor
    6. 1.5.0.Final
    7. org.projectlombok
    8. lombok
    9. 1.18.12

    2、Mapstruct的属性拷贝:

    UserPo和UserEntity的属性类型和名称完全相同。

    1. package mapstruct;
    2. import lombok.AllArgsConstructor;
    3. import lombok.Builder;
    4. import lombok.Data;
    5. import lombok.NoArgsConstructor;
    6. import java.util.Date;
    7. @Data
    8. @Builder
    9. @AllArgsConstructor
    10. @NoArgsConstructor
    11. public class UserPo {
    12. private Long id;
    13. private Date gmtCreate;
    14. private Date createTime;
    15. private Long buyerId;
    16. private Long age;
    17. private String userNick;
    18. private String userVerified;
    19. }
    1. package mapstruct;
    2. import lombok.Data;
    3. import java.util.Date;
    4. @Data
    5. public class UserEntity {
    6. private Long id;
    7. private Date gmtCreate;
    8. private Date createTime;
    9. private Long buyerId;
    10. private Long age;
    11. private String userNick;
    12. private String userVerified;
    13. }

    定义mapstruct接口,在接口上打上@Mapper注解。

    接口中有一个常量和一个方法,常量的值是接口的实现类,这个实现类是Mapstruct默认帮我们实现的,下文会讲到。定义了一个po2entity的转换方法,表示把入参UserPo对象,转换成UserEntity。注意@Mapper是Mapstruct的注解。

    1. package mapstruct;
    2. import org.mapstruct.Mapper;
    3. import org.mapstruct.factory.Mappers;
    4. @Mapper
    5. public interface IPersonMapper {
    6. IPersonMapper INSTANCT = Mappers.getMapper(IPersonMapper.class);
    7. UserEntity po2entity(UserPo userPo);
    8. }

    3、Mapstruct 性能优于 BeanUtils 的原因

    Java程序执行的过程,是由编译器先把java文件编译成class字节码文件,然后由JVM去解释执行class文件。Mapstruct正是在java文件到class这一步帮我们实现了转换方法,即做了预处理,提前编译好文件,如果用过lombok的同学一定能理解其好处,通过查看class文件,可以看出IPersonMapper被打上org.mapstruct.Mapper注解后,编译器自动会帮我们生成一个实现类IPersonMapperImpl,并实现了po2entity这个方法。

    BeanUtils转换的原理是使用的反射,反射的效率相对来说是低的,因为jvm优化在这种场景下有可能无效,所以在对性能要求很高或者经常被调用的程序中,尽量不要使用。我们平时在研发过程中,也会遵守这个原则,非必要,不反射。 

  • 相关阅读:
    dockerfile介绍与使用案例
    MySQL详细学习教程(建议收藏)
    第五话、离职前被老板威胁是一种什么样的体验
    一线大厂软件测试流程(思维导图)详解
    python之self的正确理解和访问限制的有关内容
    pipeline agent分布式构建
    日记---目标检测
    照片编辑和管理软件:Lightroom Classic 2022 Mac
    论文阅读(3) 用气泡PIV测量加利福尼亚海狮推进冲程的速度场
    Github上面的这个Nacos2.1多数据库集成适配项目真心不错:Nacos-MultiDataSource
  • 原文地址:https://blog.csdn.net/qq_36581713/article/details/127839636