【Java基础】基于动态代理优雅高性能的拷贝对象?BeanCopier

1、场景:微服务层与层之间进行对象的拷贝

微服务里面为了代码层次结构清晰,一般会进行分层,DAO层,Servic层,Controller。不同层使用不同后缀对象来进行数据传递

  • DAO层一般会使用 DO 对象来进行传递
  • Service层一般会使用 DTO 对象来进行传递
  • Controller层一般会使用VO 对象来进行传递

层与层之前进行传递数据的时候,往往对象之间的属性类似,就会重写对象的clone方法,进行对象的拷贝

比如将 DO 对象转换为 DTO 对象,或者 DTO 对象转换为 VO 对象。如何优化高性能的实现对象的拷贝呢?

2、问题:如何优化高性能的实现对象的拷贝呢?将DO对象转换为DTO对象,或者将DTO对象转换为VO对象?

3.1 常见的方法

  1. apache的BeanUtils:反射

  2. apache的PropertyUtils:反射

  3. spring的BeanUtils:反射

3.2 存在的问题

上述工具类都是采用反射的方式,来进行数据的拷贝,但是反射的性能是很差的,之前已经有很多人对这几种Bean属性拷贝工具做过了性能测试了,但是发现上面三种的性能都是很差的,不建议使用。

3.3 解决方案

答案:采用cglib的BeanCopier来进行对象的拷贝,底层原理是使用动态代理,性能很高,达到上面反射方式的几十倍甚至数百倍

4、使用BeanCopier来进行对象的拷贝(实战)

4.1 引入依赖

<!--cglib的BeanCopier需要的依赖-->
        <dependency>
            <groupId>asm</groupId>
            <artifactId>asm</artifactId>
            <version>3.3.1</version>
        </dependency>

        <dependency>
            <groupId>asm</groupId>
            <artifactId>asm-commons</artifactId>
            <version>3.3.1</version>
        </dependency>

        <dependency>
            <groupId>asm</groupId>
            <artifactId>asm-util</artifactId>
            <version>3.3.1</version>
        </dependency>

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib-nodep</artifactId>
            <version>3.2.4</version>
        </dependency>

4.2 3 BeanCopier工具类的编写


/**
 * BeanCopier工具类
 *
 * @version:v1.0
 */
public class BeanCopierUtils {

    /**
     * BeanCopier 缓存Map
     */
    public static Map<String, BeanCopier> beanCopierCacheMap = new HashMap<>();

    /**
     * @param source 源对象
     * @param target 目标对象
     * @return org.springframework.cglib.beans.BeanCopier
     * 将source对象的属性拷贝到target对象中去
     * @date 2021/2/6
     */
    public static void copyProperties(Object source, Object target) throws Exception {
        /** Map 缓存Key*/
        String cacheKey = source.getClass().toString() + target.getClass().toString();
        BeanCopier beanCopier = null;

        // 双重交易锁,防止并发问题发生
        if (!beanCopierCacheMap.containsKey(cacheKey)) {
            synchronized (BeanCopierUtils.class) {
                if (!beanCopierCacheMap.containsKey(cacheKey)) {
                    beanCopier = BeanCopier.create(source.getClass(), target.getClass(), false);
                } else {
                    beanCopier = beanCopierCacheMap.get(cacheKey);
                }
            }
        } else {
            beanCopier = beanCopierCacheMap.get(cacheKey);
        }

        assert beanCopier != null;
        beanCopier.copy(source, target, null);
    }
}

4.2.4 DO类和DTO类

/**
 *
 * @Version:v1.0
 */
public class PriorityDO {

    /**
     * 主键
     */
    private Long id;

    ...
	...

    /**
     * 创建时间
     */
    private Date gmtCreate;

    /**
     * 更新时间
     */
    private Date gmtModified;



    /**
     * 克隆方法
     *
     * @param clazz 目标class对象
     * @return T 克隆后的对象
     * @date 2021/2/5
     */
    public <T> T clone(Class<T> clazz) {
        T target = null;
        try {
            target = clazz.newInstance();
            BeanCopierUtils.copyProperties(this, target);
        } catch (Exception e) {
            logger.error("PriorityNode.clone error,clazz : {}", clazz, e);
        }
        return target;
    }
}

/**
 * 权限节点
 *
 * @Version:v1.0
 */
public class PriorityDTO {

    /**
     * 主键
     */
    private Long id;

    ...
	...

    /**
     * 创建时间
     */
    private Date gmtCreate;

    /**
     * 更新时间
     */
    private Date gmtModified;



    /**
     * 克隆方法
     *
     * @param clazz 目标class对象
     * @return T 克隆后的对象
     * @date 2021/2/5
     */
    public <T> T clone(Class<T> clazz) {
        T target = null;
        try {
            target = clazz.newInstance();
            BeanCopierUtils.copyProperties(this, target);
        } catch (Exception e) {
            logger.error("PriorityNode.clone error,clazz : {}", clazz, e);
        }
        return target;
    }
}

4.2.5 对象拷贝

 public static void main(String[] args) throws Exception {
        PriorityDO source = new PriorityDO();
        // 给resource设置各种属性
        ...
        // 拷贝属性到指定对象类型里面
        PriorityDTO target = source.clone(PriorityDTO.class);
        System.out.println(JSON.toJSONString(target));
    }

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值