用 cglib 的 BeanCopier 替换其他工具的 BeanUtils 来减少你的 Bean 拷贝时间

  • 开头

Bean 拷贝的工具有很多,有 Apache BeanUtils、Spring BeanUtils、Mapstruct、cglib BeanCopier 等等

Apache 和 Spring 的 BeanUtils 效率并不是我想要的,而使用 Mapstruct 又太繁琐了

那有没有简单易用的,而且效率还比较高的呢?这就是我这篇文章要讲述的主要内容

  • Bean 拷贝工具的区别

BeanUtils 通过反射进行属性赋值操作

BeanCopier 使用 cglib 动态代理生成带有 get/set 方法的类进行赋值

BeanCopier 是生成字节码执行,所以 BeanCopier 的性能接近手写

Mapstruct 类似与 lombok,在编译期间帮你生成一个实现类,性能最好

  • BeanCopier 使用

创建两个类,模拟转换

@Data
public class AuthUserVO {

    private String name;
    private Integer age;

}
@Data
public class AuthUser {

    private String name;
    private Integer age;

}
public static void main(String[] args) {
        AuthUserVO authUserVO = new AuthUserVO();
        authUserVO.setName("张三");
        authUserVO.setAge(25);

        AuthUser authUser = new AuthUser();
        
        BeanCopier beanCopier = BeanCopier.create(authUserVO.getClass(), authUser.getClass(), false);
        beanCopier.copy(authUserVO, authUser, null);

        System.out.println(authUser);
    }

输出结果

 BeanCopier 只能拷贝类型相同并且属性名也相同的,但是可以自己实现转换规则,本文不详细讲述此用法

扫描二维码关注公众号,回复: 16326393 查看本文章
  • BeanCopier 实战使用

封装 BeanCopier 工具类

/**
 * Bean 转换高性能工具
 * 如果source或者targetSupplier只要有一个为null就返回null
 * 调用方如果把null进行转换,那就是想转换为null,为不为空应该由调用方自己负责
 */
public class ConvertUtil {

    private ConvertUtil() {}

    /**
     * BeanCopier缓存(享元模式)
     */
    private static final Map<CopierIdentity, BeanCopier> BEAN_COPIER_MAP = new ConcurrentHashMap<>();

    /**
     * 将source对象的属性拷贝到target对象中去
     *
     * @param source source对象
     * @param target target对象
     */
    public static void copyProperties(Object source, Object target) {
        if (null == source || null == target) {
            return;
        }
        // 作为 Key,
        CopierIdentity identity = CopierIdentity.create(source.getClass(), target.getClass());
        // 查看 concurrentHashMap 的实现方法介绍可以得知该方法为原子方法,保证了线程安全
        // 复用 BeanCopier 对象,因为创建比较耗时
        BeanCopier beanCopier = BEAN_COPIER_MAP.computeIfAbsent(identity, v -> BeanCopier.create(source.getClass(), target.getClass(), false));
        beanCopier.copy(source, target, null);
    }

    public static <S, T> T single(S source, Supplier<T> targetSupplier) {
        return single(source, targetSupplier, null);
    }

    /**
     * 转换对象
     *
     * @param source         源对象
     * @param targetSupplier 目标对象供应方
     * @param callBack       回调方法
     * @param <S>            源对象类型
     * @param <T>            目标对象类型
     * @return 目标对象
     */
    public static <S, T> T single(S source, Supplier<T> targetSupplier, ConvertCallBack<S, T> callBack) {
        if (null == source || null == targetSupplier) {
            return null;
        }

        T target = targetSupplier.get();
        copyProperties(source, target);
        if (null != callBack) {
            callBack.callBack(source, target);
        }

        return target;
    }

    public static <S, T> List<T> list(List<S> sources, Supplier<T> targetSupplier) {
        return list(sources, targetSupplier, null);
    }

    /**
     * 转换对象
     *
     * @param sources        源对象list
     * @param targetSupplier 目标对象供应方
     * @param callBack       回调方法
     * @param <S>            源对象类型
     * @param <T>            目标对象类型
     * @return 目标对象list
     */
    public static <S, T> List<T> list(List<S> sources, Supplier<T> targetSupplier, ConvertCallBack<S, T> callBack) {
        List<T> list = new ArrayList<>();
        if (null == sources || null == targetSupplier) {
            return list;
        }
        for (S source : sources) {
            list.add(single(source, targetSupplier, callBack));
        }
        return list;
    }


    /**
     * 回调接口
     *
     * @param <S> 源对象类型
     * @param <T> 目标对象类型
     */
    @FunctionalInterface
    public interface ConvertCallBack<S, T> {
        /**
         * 回调方法
         * @param t 目标对象
         * @param s 源对象
         */
        void callBack(S t, T s);
    }

    private static class CopierIdentity {
        private Class<?> source;
        private Class<?> target;

        private static CopierIdentity create(Class<?> source, Class<?> target) {
            CopierIdentity identity = new CopierIdentity();
            identity.source = source;
            identity.target = target;
            return identity;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (!(o instanceof CopierIdentity)) {
                return false;
            }
            CopierIdentity identity = (CopierIdentity) o;
            return Objects.equals(source, identity.source) && Objects.equals(target, identity.target);
        }

        @Override
        public int hashCode() {
            return Objects.hash(source, target);
        }
    }

}

单个对象转换

  • 使用方式1
public static void main(String[] args) {
        AuthUserVO authUserVO = new AuthUserVO();
        authUserVO.setName("张三");
        authUserVO.setAge(25);

        AuthUser authUser = new AuthUser();
        ConvertUtil.copyProperties(authUserVO, authUser);

        System.out.println(authUser);
    }
  • 使用方式2
public static void main(String[] args) {
        AuthUserVO authUserVO = new AuthUserVO();
        authUserVO.setName("张三");
        authUserVO.setAge(25);

        AuthUser authUser = ConvertUtil.single(authUserVO, AuthUser::new);

        System.out.println(authUser);
    }
  • 使用方式3

使用 Java 8 的函数式编程解决字段类型不一样或者字段属性名不一样的问题,工具类已封装

创建两个类,模拟转换

@Data
public class AuthUserVO {

    private String name;
    private Integer age;

}
@Data
public class AuthUser {

    private String username;
    private int age;

}
public static void main(String[] args) {
        AuthUserVO authUserVO = new AuthUserVO();
        authUserVO.setName("张三");
        authUserVO.setAge(25);

        AuthUser authUser = ConvertUtil.single(authUserVO, AuthUser::new, (s, t) -> {
            t.setUsername(s.getName());
            t.setAge(s.getAge());
        });

        System.out.println(authUser);
    }

输出结果

 转换集合

  • 使用方式1
public static void main(String[] args) {
        List<AuthUserVO> authUserVOList = new ArrayList<>();
        AuthUserVO authUserVO = new AuthUserVO();
        authUserVO.setName("张三");
        authUserVO.setAge(25);
        authUserVOList.add(authUserVO);

        List<AuthUser> authUserList = ConvertUtil.list(authUserVOList, AuthUser::new);

        System.out.println(authUserList);
    }
  • 使用方式2
public static void main(String[] args) {
        List<AuthUserVO> authUserVOList = new ArrayList<>();
        AuthUserVO authUserVO = new AuthUserVO();
        authUserVO.setName("张三");
        authUserVO.setAge(25);
        authUserVOList.add(authUserVO);

        List<AuthUser> authUserList = ConvertUtil.list(authUserVOList, AuthUser::new, (s, t) -> {
            t.setUsername(s.getName());
            t.setAge(s.getAge());
        });

        System.out.println(authUserList);
    }

输出结果

猜你喜欢

转载自blog.csdn.net/Eighteen_y/article/details/130005703