乐趣区

关于java:Vo对象Dao对象Dto对象的部分属性复制BeanCopierBeanUtils

在理论的开发中,存在 Vo 对象,Dao 对象,DTO 对象的局部属性复制的问题
比拟笨的方法 A.setxxx(B.getXXX),费时又费劲,怎么解决这个问题呢?
举荐应用两种对象属性复制的方法:
对象属性拷贝的两种形式:
1、BeanUtils(留神 BeanUtils 应用的是 spring 的 Beanutils 的)
2、BeanCopier

先筹备三个 Vo 对象,Dao 对象,Dto 对象,前面咱们对这三个对象进行拷贝和复制。

@Data
@AllArgsConstructor
public class UserDo {

    private int id;
    private String userName;
    private LocalDateTime gmtBroth;
    private BigDecimal balance;
}
@Data
public class UserDto {
    private int id;
    private String userName;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserVo {
    private int id;
    private String userName;
    private String gmtBroth;
    private String agevo;
}

第一种形式应用 BeanUtils 进行拷贝

import org.springframework.beans.BeanUtils;
@Slf4j
public class BeanCopyTest {public static void main(String[] args) {UserDo userDo=new UserDo(1,"sunyuhau", LocalDateTime.now(),new BigDecimal(100L));
    log.info("拷贝前 =="+userDo);
    UserVo userVo=new UserVo();
    BeanUtils.copyProperties(userDo,userVo);
    log.info("拷贝后 ==="+userVo);
    }
}

输入后果为:

然而这种办法耗时比拟长,线上有点不能满足需要。所以引出了第二种计划:
BeanCopier

        long startTime2=System.currentTimeMillis();
        UserDo userDo1=DataUtil.createData();
        log.info("拷贝前 userDo1:{}",userDo1);
        // 将 userDo 拷贝到 userdto,false 代表是不应用自定义转化器
        BeanCopier beanCopier=BeanCopier.create(UserDo.class,UserDto.class,false);
        UserDto userDto=new UserDto();
        // 不应用 conberter 形式,仅对两个 bean 对象属性名和类型完全相同的变量进行拷贝。beanCopier.copy(userDo1,userDto,null);
        log.info("拷贝后:userDto:{}",userDto);
        log.info("耗时:"+(System.currentTimeMillis()-startTime2));

BeanCopier 有两种形式,一个是 conberter,一个是不应用自定义的 conberter,下面的不应用自定义器的。

long startTime3=System.currentTimeMillis();
        UserDo userDo2=DataUtil.createData();
        log.info("拷贝前:{}",userDo2);
        BeanCopier.create(UserDo.class,UserVo.class,true);
        UserDo userDo3=DataUtil.createData();
        log.info("拷贝前:userDo:{}",userDo3);
        BeanCopier beanCopier1 = BeanCopier.create(UserDo.class, UserVo.class, true);
        UserConverter userConverter=new UserConverter();
        UserVo uservo3=new UserVo();
        beanCopier1.copy(userDo3,uservo3,userConverter);
        log.info("拷贝后 ==userDo:{}",uservo3);
        log.info("耗时 3:"+(System.currentTimeMillis()-startTime3));

/**
 * 自定义的 user 对象的转化器
 * 一旦应用 converter,BeanCopier 只应用 converter 定义的规定去拷贝,所以在 convert() 办法中要思考所有的属性
 * 并且 converter 会是对象拷贝速度变慢。*
 */
public class UserConverter implements Converter {DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss");
    @Override
    public Object convert(Object o, Class aClass, Object o1) {if(o instanceof Integer){return o;}else if(o instanceof LocalDateTime){LocalDateTime date=(LocalDateTime)o;
            return dateTimeFormatter.format(date);
        }else if(o instanceof BigDecimal){BigDecimal bigDecimal=(BigDecimal)o;
            return bigDecimal.toPlainString();}
        return o;
    }
}

不论使不应用自定义的转化器,都有还有一个弊病,就是每次都初始化 BeanCopier beanCopier=BeanCopier.create(UserDo.class,UserDto.class,false);
BeanCopier beanCopier1 = BeanCopier.create(UserDo.class, UserVo.class, true);
这个点是不必须的。所以能够将这个初始化到内存中,这样就没有必要每次都生成 BeanCopier。
具体的做法如下:


import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.beans.BeanCopier;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public  class BeanCopierWithCacheUtil {private static  ConcurrentHashMap<String,BeanCopier> BEAN_COPIERS = new ConcurrentHashMap<>() ;

    static void beanCopierWithCache() {List<UserDo> userDOList = DataUtil.createDataList(10000);
        long start = System.currentTimeMillis();
        List<UserDto> userDtos = new ArrayList<>();
        userDOList.forEach(userDo -> {UserDto userDTO = new UserDto();
            // 将 userDo 对象的参数,复制到 userDTO 对象
            copy(userDo, userDTO);
            userDtos.add(userDTO);
        });
        log.info("BeanCopier 加缓存后 costTime: {}ms", System.currentTimeMillis() - start);

    }

    /**
     * 将不必类型转化的 copier = BeanCopier.create(srcObj.getClass(), destObj.getClass(), false) 放入内存
     * 第一次初始化的时候将 BeanCopier,初始到内存中,下次再次应用时。间接应用。* @param srcObj
     * @param destObj
     */
    public static void copy(Object srcObj, Object destObj) {String key = genKey(srcObj.getClass(), destObj.getClass());
        BeanCopier copier = null;
        if (!BEAN_COPIERS.containsKey(key)) {copier = BeanCopier.create(srcObj.getClass(), destObj.getClass(), false);
            BEAN_COPIERS.put(key, copier);
        } else {copier = BEAN_COPIERS.get(key);
        }
        copier.copy(srcObj, destObj, null);
    }

    /**
     * 将转化的类的名字和被转化类型的名字作为 key,保留到内存中
     * @param srcClazz
     * @param destClazz
     * @return
     */
    private static String genKey(Class<?> srcClazz, Class<?> destClazz) {return srcClazz.getName() + destClazz.getName();}

}
  log.info("+++++++++++BeanCopier 放在缓存中 +++++++++++++++");
        // 留神第一次是初始化 BeanCopier,工夫会比拟长
        BeanCopierWithCacheUtil beanCopierWithCacheUtil=new BeanCopierWithCacheUtil();
        beanCopierWithCacheUtil.beanCopierWithCache();

这样耗时就会更短,转化的效率就更高了。
本篇文章由一文多发平台 ArtiPub 主动公布

退出移动版