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是集合类,Collection和Map,会尝试序列化方式(实现Serializable)。
其他对象若有无参构造,会进一步调用fastbean复制对象,否则会尝试序列化方式。
尝试失败将不会进行深拷贝。(浅拷贝)
性能评测
使用到的是
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