关于我封装了BeanCopier这件事

2,939 阅读3分钟

Bean的拷贝我们不陌生,经常与之打交道,看了很多评测,抛开功能不说,性能上前三大致就是原生的get/set、MapStruct、cglib bean copy。

之所以需要是用beanCopy,就是因为大量的get/set不雅观(绝对不是我们懒)。

MapStruct是在编译时期生成的代码,但是其使用让我觉得繁琐。

cglib使用动态字节码技术生成class文件,在全局缓存的copier之后速度也是非常的快。但是也有很多不方便的地方,

我结合实际需求,对它动了心❤。

一些缺点:

  • 泛型安全检查
  • 转换器使用不方便
  • 在某些版本setter会报错
  • 不支持基本类型和包装类转换
  • 不支持字段的映射与忽略
  • 浅拷贝
  • 会设置NULL值
  • 会覆盖原有值

基于以上使用过程中的不便之处,我封装了一个fastbean解决上述问题。与原生的beancopier相比,更灵活了,比大部分反射框架快很多。

使用

    <dependency>
        <groupId>io.github.cqpsjsl</groupId>
        <artifactId>fastbean</artifactId>
        <version>2.0.1</version>
    </dependency>

BeanCopyUtil封装了常用便捷操作。

基本使用

BeanCopyUtil.copy(userDO, userDTO);

链式调用

BeanCopyUtil.chain(userDO,userDTO) // 开启链式调用
        // 将username复制到name
        .nameMapping(UserDTO::getName, UserDO::getUsername) // 字段映射(可选)
        .nameMapping(UserDTO::getId, UserDO::getIds) // 字段映射(可选)
        // address将不会被赋值
        .ignore(UserDTO::getAddress) // 字段忽略(可选
        // 若无特殊需求 如LocalDateTime转Long,可不用配置
        .converterChain(new DefaultConverterChain()) // 自定义转换器链(可选)
        .converter(new EnumConverter()) // 往转换器链(自定义/默认) 添加转换器 (可选)
        .copy(); // 复制

拷贝规则

FastBean是使用的get、set来操作的,请保证你的javaBean符合规范。FastBean默认是不会设置NULL值不会覆盖值浅拷贝,如果需要改变它,有两种方式,全局和局部。

全局设置

你需要在使用之前执行以下配置就好。只需要设置一次。

FastBeanStrategy fastBeanStrategy = new FastBeanStrategy();
// 开启深拷贝
fastBeanStrategy.setCopyStrategy(StrategyConstant.DEEP_COPY);
// 能够设置NULL值
fastBeanStrategy.setSetNullStrategy(StrategyConstant.CAN_SET_NULL);
// 能够覆盖值
fastBeanStrategy.setCoverStrategy(StrategyConstant.CAN_SET_COVER);
// 设置全局配置
FastBeanCopier.setGlobalFastBeanStrategy(fastBeanStrategy);

局部配置

在局部自定义并不会影响全局使用如下

BeanCopyUtil.chain(userDO, userDTO)
  // 允许值覆盖 单次生效
  .canCover() 
  // 允许设置NULL值 单次生效
  .canSetNull()
  // 深拷贝 单次生效
  .isDeep(true)
  .copy();

深拷贝规则

当你开启了深拷贝之后,fastbean会尝试进行深拷贝,如果你的Bean实现了FastCloneable,会优先调用Object.clone()。注意,Object.clone()是浅拷贝。

如果你的Bean是集合类,CollectionMap,会尝试序列化方式(实现Serializable)。

其他对象若有无参构造,会进一步调用fastbean复制对象,否则会尝试序列化方式。

尝试失败将不会进行深拷贝。(浅拷贝)

性能评测

使用到的是

github.com/arey/java-o…

Benchmark                    (type)   Mode  Cnt         Score         Error  Units
MapperBenchmark.mapper       Manual  thrpt   25  29946646.768 ± 1792755.706  ops/s
MapperBenchmark.mapper    MapStruct  thrpt   25  31583496.032 ± 1250708.021  ops/s
MapperBenchmark.mapper        Selma  thrpt   25  27705458.501 ± 2373389.175  ops/s
MapperBenchmark.mapper      JMapper  thrpt   25  30790834.537 ± 1241497.414  ops/s
MapperBenchmark.mapper        datus  thrpt   25  19200882.756 ±  594521.356  ops/s
MapperBenchmark.mapper        Orika  thrpt   25   5625364.039 ±  235479.171  ops/s
MapperBenchmark.mapper  ModelMapper  thrpt   25    291876.025 ±   14164.851  ops/s
MapperBenchmark.mapper         BULL  thrpt   25    129208.891 ±    6574.186  ops/s
MapperBenchmark.mapper        Dozer  thrpt   25    108005.728 ±    8313.390  ops/s
MapperBenchmark.mapper        ReMap  thrpt   25    676239.915 ±   54571.419  ops/s
MapperBenchmark.mapper     fastbean  thrpt   25   5665789.825 ±  105562.151  ops/s
​

结论

总的来说,扩展了beancopier,丰富了功能,提高了灵活性,性能也极高。可以尝试使用一下?

第一次分享文章,希望大佬们提提意见o(╥﹏╥)o