BeanUtils.copyProperties的使用场景:DO、DTO、VO之间的转换BeanUtils.copyProperties的避坑替代工具类——MapstructBeanUtils.copyProperties的使用场景涉及到的DO、DTO、VO之间的转换,我们大多使用Spring框架里的BeanUtils.copyProperties来做对象转换,以下举例对比使用工具和不使用工具:
DTO和VO的转换
- @Data
- public class OrderDTO {
- private long id;
-
- private Long userId;
-
- private String orderNo;
-
- private Date gmtCreated;
- }
- @Data
- public class OrderVO {
- private long id;
-
- private long userId;
-
- private String orderNo;
-
- private Date gmtCreated;
- }
不使用工具转换:
- public static void main(String[] args) {
- OrderDTO orderDTO = new OrderDTO();
- orderDTO.setId(1L);
- orderDTO.setUserId(123L);
- orderDTO.setOrderNo("20210518000001");
- orderDTO.setGmtCreated(new Date());
-
- OrderVO orderVO = new OrderVO();
- orderVO.setId(orderDTO.getId());
- orderVO.setUserId(orderDTO.getUserId());
- orderVO.setOrderNo(orderDTO.getOrderNo());
- orderVO.setGmtCreated(orderDTO.getGmtCreated());
- }
使用工具转换:
- OrderVO orderVO = new OrderVO();
- BeanUtils.copyProperties(orderDTO, orderVO);
-
- //使用自定义工具---如下
- OrderVO orderVO=BeanUtil.copyProperties(OrderVO.class, orderDTO);
以下是自定义的一个工具类:
BeanUtil(包装BeanUtils)
- package com.test.utils;
-
- import java.util.*
- import org.springframword.beans.Beanutils;
- import org.springframword.util.CollectionUtils;
-
- public class BeanUtil extends BeanUtils(
- public BeanUtil(){
- }
-
- public statci
List Dto2List(Class destType, List orig) { - List
dest = new ArratList(); - if (CollectionUtils.isEmpty(orig)){
- return dest;
- }else {
- Iterator it = orig.iterator();
- while(it.hasNext()){
- E e = it.next();
- T obj = BeanUtils.instantiateClase(destType);
- BeanUtils.copyProperties(e, obj);
- dest.add(obj);
- }
- return dest;
- }
- }
-
- public statci
T copyProperties(Class destType, Object srcObject) { - if (srcObject == null){
- return null;
- } else {
- T obj = BeanUtils.instantiateClase(destType);
- BeanUtils.copyProperties(srcObject, obj);
- return obj;
- }
- }
二、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,可以去仓库中查看最新版本。
-
-
org.mapstruct -
mapstruct -
1.5.0.Final -
-
-
org.mapstruct -
mapstruct-processor -
1.5.0.Final -
-
-
org.projectlombok -
lombok -
1.18.12 -
2、Mapstruct的属性拷贝:
UserPo和UserEntity的属性类型和名称完全相同。
- package mapstruct;
-
- import lombok.AllArgsConstructor;
- import lombok.Builder;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- import java.util.Date;
-
- @Data
- @Builder
- @AllArgsConstructor
- @NoArgsConstructor
- public class UserPo {
- private Long id;
- private Date gmtCreate;
- private Date createTime;
- private Long buyerId;
- private Long age;
- private String userNick;
- private String userVerified;
- }
- package mapstruct;
-
- import lombok.Data;
-
- import java.util.Date;
-
- @Data
- public class UserEntity {
- private Long id;
- private Date gmtCreate;
- private Date createTime;
- private Long buyerId;
- private Long age;
- private String userNick;
- private String userVerified;
- }
定义mapstruct接口,在接口上打上@Mapper注解。
接口中有一个常量和一个方法,常量的值是接口的实现类,这个实现类是Mapstruct默认帮我们实现的,下文会讲到。定义了一个po2entity的转换方法,表示把入参UserPo对象,转换成UserEntity。注意@Mapper是Mapstruct的注解。
-
- package mapstruct;
-
- import org.mapstruct.Mapper;
- import org.mapstruct.factory.Mappers;
-
- @Mapper
- public interface IPersonMapper {
- IPersonMapper INSTANCT = Mappers.getMapper(IPersonMapper.class);
- UserEntity po2entity(UserPo userPo);
- }
3、Mapstruct 性能优于 BeanUtils 的原因
Java程序执行的过程,是由编译器先把java文件编译成class字节码文件,然后由JVM去解释执行class文件。Mapstruct正是在java文件到class这一步帮我们实现了转换方法,即做了预处理,提前编译好文件,如果用过lombok的同学一定能理解其好处,通过查看class文件,可以看出IPersonMapper被打上org.mapstruct.Mapper注解后,编译器自动会帮我们生成一个实现类IPersonMapperImpl,并实现了po2entity这个方法。

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