Bean对象的拷贝方法BeanCopier和BeanUtils

本文介绍了Java中用于对象拷贝的BeanCopier和BeanUtils。BeanCopier在属性名和类型完全相同时进行拷贝,支持自定义转换器,但类型不同的属性不会拷贝。当创建BeanCopier实例并缓存时,拷贝速度快。相比之下,Spring的BeanUtils更稳定,但性能稍逊,适用于属性类型相同的对象拷贝。

1. BeanCopier

默认只复制名称类型相同的字段,对date为空的情况不进行复制。把相同的进行复制,把不同的,也就是需要我们个性化的一些字段,单独出来用set来赋值,这样程序就会很明确,重点也就聚焦在了不同的地方。
BeanCopier支持两种方式:
一种是不使用Converter的方式,仅对两个bean间属性名和类型完全相同的变量进行拷贝;
另一种则引入Converter,可以对某些特定属性值进行特殊操作。

  import org.springframework.cglib.beans.BeanCopier;
  //1、source源;2、target目标;把源中的属性复制到目标中
  BeanCopier.create(Source.class, Target.class, false)
                  .copy(source, target, null);

注:即使源类型是原始类型(int, short和char等),目标类型是其包装类型(Integer, Short和Character等),或反之,都不会被拷贝

源码:

public static BeanCopier create(Class source, Class target, boolean useConverter) {
        BeanCopier.Generator gen = new BeanCopier.Generator();
        gen.setSource(source);
        gen.setTarget(target);
        gen.setUseConverter(useConverter);
        return gen.create();
    }

自定义转换器Converter
已知,当源和目标类的属性类型不同时,不能拷贝该属性,此时我们可以通过实现Converter接口来自定义转换器

public class UserConverter implements Converter{}
  1. 一旦使用Converter,BeanCopier只使用Converter定义的规则去拷贝属性,所以在convert()方法中要考虑所有的属性。
  2. 使用Converter会使对象拷贝速度变慢。

BeanCopier总结

  1. 当源类和目标类的属性名称、类型都相同,拷贝没问题。
  2. 当源对象和目标对象的属性名称相同、类型不同,那么名称相同而类型不同的属性不会被拷贝。注意,原始类型(int,short,char)和 他们的包装类型,在这里都被当成了不同类型,因此不会被拷贝。
  3. 源类或目标类的setter比getter少,拷贝没问题,此时setter多余,但是不会报错。
  4. 源类和目标类有相同的属性(两者的getter都存在),但是目标类的setter不存在,此时会抛出NullPointerException。

2. BeanUtils

Apache和Spring均有BeanUtils工具类, Apache的BeanUtils稳定性与效率都不行;Spring的BeanUtils比较稳定,不会因为量大了,耗时明显增加,故一般都使用Spring的BeanUtils。

import org.springframework.beans.BeanUtils

public static void copyProperties(Object source, Object target) throws BeansException {
        copyProperties(source, target, (Class)null, (String[])null);
    }

Spring中的BeanUtils,其中实现的方式很简单,就是对两个对象中相同名字的属性进行简单get/set,仅检查属性的可访问性。成员变量赋值是基于目标对象的成员列表,并且会跳过ignore的以及在源对象中不存在的,所以这个方法是安全的,不会因为两个对象之间的结构差异导致错误,但是必须保证同名的两个成员变量类型相同。

BeanCopier拷贝速度比BeanUtils快,性能瓶颈出现在创建BeanCopier实例(create)的过程中。
所以,把创建过的BeanCopier实例放到缓存中,下次可以直接获取,提升性能

<think>我们正在讨论cglib的BeanCopier.create方法。根据引用[1]引用[4]中的代码片段,我们可以了解到BeanCopier.create方法用于创建一个BeanCopier对象,该对象用于将一个JavaBean的属性复制到另一个JavaBean中。 方法签名: BeanCopier.create(Class source, Class target, boolean useConverter) 参数解释: - source:源对象的类,即从哪个对象复制属性。 - target:目标对象的类,即复制到哪个对象。 - useConverter:一个布尔值,表示是否使用自定义转换器(Converter)。如果设置为true,则在复制过程中会调用Converter进行类型转换;如果设置为false,则BeanCopier只会复制同名且同类型的属性,如果遇到类型不同或名称不同的属性,则会报错。 根据引用[1]中的说明,第三个参数useConverter的作用是决定是否开启转换器。默认情况下(即useConverter=false),BeanCopier只会复制同名且同类型的属性,如果遇到类型不同的属性,就会报错。而如果设置为true,则可以通过传入一个Converter来实现类型转换。 引用[4]中的案例代码展示了如何使用BeanCopier.create方法: ```java public static <T> T beanConvert(Object from, Class<T> clazz, Converter converter) { if (from == null) return null; try { T t = clazz.newInstance(); BeanCopier beanCopier = BeanCopier.create(from.getClass(), clazz, converter != null); beanCopier.copy(from, t, converter); return t; } catch (Exception e) { // 异常处理 return null; } } ``` 在这段代码中,create方法的第三个参数是`converter != null`,这意味着如果调用者传递了一个非空的converter,那么就开启转换器(useConverter=true),否则就不开启(useConverter=false)。然后,在调用copy方法时,将converter传入(如果开启转换器,则传入的converter会被使用)。 另外,根据引用[2]引用[3]可知,BeanCopier在性能上优于Spring的BeanUtilsApache的BeanUtils,因此推荐使用。 总结:BeanCopier.create方法用于创建一个BeanCopier实例,该实例根据useConverter参数决定是否使用转换器来处理属性复制过程中的类型转换问题。 §§相关问题§§ 1.BeanCopier.create方法中的useConverter参数设置为truefalse有什么区别? 2.如何自定义一个Converter来处理BeanCopier复制过程中的类型转换? 3.BeanCopier在复制属性时,对于同名的属性但类型不同的情况,在没有开启Converter时会如何处理? </think>### `BeanCopier.create` 的含义解析 `BeanCopier.create` 是 **Cglib 库**中用于创建**高性能 Java Bean 属性拷贝工具**的核心方法。其作用是根据指定的源对象目标对象类型,动态生成高效的字节码级拷贝器。以下是详细解析: #### 方法签名与参数 ```java BeanCopier copier = BeanCopier.create(Source.class, Target.class, boolean useConverter); ``` 1. **`Source.class`** - 源对象的 Class 类型(被拷贝Bean 类型)。 2. **`Target.class`** - 目标对象的 Class 类型(接收拷贝Bean 类型)。 3. **`useConverter`(关键参数)** - `true`:开启**自定义类型转换**,允许处理不同类型属性(如 `String` → `Integer`)或复杂转换逻辑[^1][^4]。 - `false`:**严格模式**,要求属性名类型完全匹配,否则抛出异常[^1]。 #### 底层机制 - **字节码生成**:在初始化时动态生成优化后的字节码(无需反射),性能远超反射工具(如 Apache `BeanUtils`)[^2][^3]。 - **缓存复用**:生成的 `BeanCopier` 实例可缓存复用,避免重复创建开销。 #### 使用场景对比 | 模式 (`useConverter`) | 适用场景 | 风险 | |------------------------|----------|------| | `false`(默认) | 源/目标对象属性完全同名同类型 | 类型不匹配时报错 | | `true` | 需类型转换(如 `Date` → `String`) | 需自行实现 `Converter` 处理逻辑 | #### 完整流程示例 ```java // 1. 创建带转换器的 BeanCopier(开启 useConverter) BeanCopier copier = BeanCopier.create(UserDTO.class, UserEntity.class, true); // 2. 自定义 Converter(处理类型转换逻辑) Converter converter = (srcValue, targetType, method) -> { if (srcValue instanceof Date) { return new SimpleDateFormat("yyyy-MM-dd").format((Date)srcValue); // Date → String } return srcValue; // 其他情况直接返回 }; // 3. 执行拷贝 UserDTO dto = new UserDTO(new Date(), 25); UserEntity entity = new UserEntity(); copier.copy(dto, entity, converter); // 使用转换器 ``` #### 性能优势 - 根据基准测试,`BeanCopier` 性能显著优于其他工具[^2]: $$ \text{性能排序:} \quad \text{Cglib BeanCopier} \gg \text{Spring BeanUtils} \gg \text{Apache PropertyUtils} \gg \text{Apache BeanUtils} $$ #### 最佳实践 - **优先用 `useConverter=false`**:若属性完全匹配,避免转换器开销。 - **谨慎实现 `Converter`**:自定义转换需覆盖所有边界情况(如空值、类型异常)[^4]。 - **替代警告方案**:阿里规约推荐用 `BeanCopier` 替换低效的 `Apache BeanUtils`[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值