Spring中的BeanUtils.copyProperties

简介: `BeanUtils.copyProperties()` 是 Spring 框架提供的工具方法,用于将一个 JavaBean 对象的属性值复制到另一个 JavaBean 对象中。主要功能包括属性拷贝、简化代码、类型转换等。该方法基于反射实现,支持属性名匹配和赋值,但仅执行浅拷贝,不支持深拷贝。使用时需注意属性名称和类型匹配,以及处理 null 值等问题。

BeanUtils.copyProperties() 是 Spring 框架中的一个工具方法,用于将一个 JavaBean 对象的属性值复制到另一个 JavaBean 对象中。其作用是将源对象的属性值复制到目标对象中,从而实现对象属性的拷贝。下面详细解释其作用和原理:

作用:

  1. 属性拷贝:将一个对象的属性值复制到另一个对象中,通常用于 DTO(数据传输对象)和领域模型对象之间的属性拷贝,以便在它们之间进行数据传输和转换。
  2. 简化代码:避免了手动逐个设置属性值的繁琐过程,提高了代码的简洁性和可读性。
  3. 类型转换:在属性值拷贝过程中,BeanUtils 可以自动进行类型转换,使得源对象和目标对象的属性类型不必完全一致。

原理:

  1. 反射:BeanUtils.copyProperties() 方法通过 Java 的反射机制来实现属性值的复制。它会获取源对象和目标对象的所有属性,并逐一进行复制。
  2. 属性名匹配:方法会通过反射机制获取源对象和目标对象的所有属性,并且会根据属性名进行匹配。只有在源对象和目标对象中具有相同名称且可访问的属性时,才会进行属性复制。
  3. 属性赋值:对于匹配的属性,会将源对象中的属性值直接赋值给目标对象的对应属性。这里的赋值操作是直接的引用赋值,不会进行类型转换或者复制属性值所引用的对象。
  4. 类型兼容性:如果源对象的属性类型与目标对象的属性类型不兼容,例如源对象的属性是基本类型,而目标对象的属性是包装类型,或者两者的属性类型不同,那么在赋值过程中会抛出类型转换异常。
  5. 属性过滤:可以通过设置参数来指定要复制的属性列表,从而实现部分属性的复制。

因此,在使用 BeanUtils.copyProperties() 方法时,需要注意确保源对象和目标对象的属性类型和名称都匹配,以避免类型转换异常或属性复制不完整的情况发生。对于类型不匹配的属性,需要提前进行类型转换或者采取其他适当的处理方式。

是浅拷贝还是深拷贝?

BeanUtils.copyProperties() 方法实现的是浅拷贝。

在浅拷贝中,只复制对象的引用,而不复制引用指向的对象。这意味着,如果源对象和目标对象的属性是对象类型(非基本数据类型),则它们在内存中引用的是同一个对象,而不是两个相互独立的对象。因此,如果修改了其中一个对象的属性,另一个对象的相应属性也会受到影响。

举例来说,假设源对象 source 和目标对象 target 都有一个属性 list,它们都引用同一个 ArrayList 对象。当使用 BeanUtils.copyProperties() 方法进行属性复制时,只会复制 list 属性的引用,而不会复制 ArrayList 对象本身。因此,如果修改了 source 对象的 list 属性,target 对象的 list 属性也会发生变化,因为它们引用的是同一个 ArrayList 对象。

如果需要进行深拷贝,即复制对象及其所有属性的副本,可以考虑使用其他工具或手动实现深拷贝逻辑,例如使用第三方库(如 Apache Commons BeanUtils 中的 BeanUtils.cloneBean() 方法)或手动递归复制对象的所有属性。

踩坑记录

1.属性名称和类型匹配问题

源对象和目标对象的属性名称要完全匹配,否则会导致部分属性无法复制或者属性值错误。另外,属性的类型也要保持一致,否则可能会发生类型转换异常。

2.深拷贝问题

BeanUtils.copyProperties() 方法进行的是浅拷贝,如果源对象的属性值是对象类型,并且被多个对象引用,那么目标对象的相应属性值也会引用同一个对象。这可能导致在修改一个对象的属性值时,其他对象的属性值也会受到影响。

java

代码解读

复制代码

//源对象
@Data  
public class SourceObject {  
private String name;  
private int age;  
private Map<String,String> map;  
}

//目标对象
@Data  
public class TargetObject {  
private String name;  
private int age;  
private Map<String,String> map;  
}

这时目标对象确实赋值了。但是如果改变map对象,目标对象也会跟着改变。

3.null 值处理

默认情况下,BeanUtils.copyProperties() 方法会将源对象中的所有非 null 属性值复制到目标对象中。如果希望忽略源对象中的 null 属性值,可以使用 BeanUtils.copyProperties() 方法的重载版本,并设置 ignoreNullSource 参数为 true

4.bean对应的属性,没有getter和setter方法

BeanUtils.copyProperties要拷贝属性值成功,需要对应的bean要有getter和setter方法。因为它是用反射拿到set和get方法再去拿属性值和设置属性值的。

5.属性是泛型,不会赋值

推荐使用hutool工具包的BeanUtil.copyProperties()

xml

代码解读

复制代码

<!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.17</version>
        </dependency>

注意以下几点:

  1. 属性名和数据类型必须匹配
  • 在源对象和目标对象之间进行属性拷贝时,属性名和数据类型必须保持一致。如果属性名或数据类型不匹配,可能会导致拷贝失败或异常。
  • 只有在目标对象已经存在对应的属性时,才会进行属性值的复制。
  1. 自动属性映射
  • 如果源对象和目标对象的属性名不一致,但是数据类型匹配,BeanUtil.copyProperties() 方法会自动进行属性映射,将源对象的属性值复制到目标对象对应的属性中。
  • 1.属性名匹配: 如果源对象和目标对象的属性名完全一致,则直接进行属性值的复制。
  • 2.驼峰命名转换:如果源对象和目标对象的属性名不完全一致,但是符合驼峰命名规范(例如:sourceName 和 targetName),则会尝试进行驼峰命名的转换。例如,将 sourceName 转换为 source_name,然后与目标对象的属性进行匹配。
  • 3.忽略大小写:属性映射时会忽略属性名的大小写。即使源对象和目标对象的属性名在大小写上有差异,也会尝试进行匹配。
  1. 支持嵌套对象的属性复制
  • BeanUtil.copyProperties() 方法支持嵌套对象的属性复制,即如果源对象和目标对象的属性包含其他对象类型的属性,也会递归地进行属性复制。
  1. 支持集合属性的复制
  • Hutool 的 BeanUtil.copyProperties() 方法支持集合属性的复制,即如果源对象和目标对象的属性包含集合类型(如 List、Set、Map 等)的属性,也会进行正确的复制。
  1. 处理 null 值
  • 默认情况下,如果源对象的属性值为 null,BeanUtil.copyProperties() 方法不会将该属性复制到目标对象中,目标对象的属性值保持不变。这种行为可以避免将 null 值赋给目标对象的属性。
  1. 属性是泛型,不会赋值

转载来源:https://juejin.cn/post/7356772920277155890

目录
打赏
0
0
0
0
190
分享
相关文章
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 介绍
本课介绍Spring Boot集成Thymeleaf模板引擎。Thymeleaf是一款现代服务器端Java模板引擎,支持Web和独立环境,可实现自然模板开发,便于团队协作。与传统JSP不同,Thymeleaf模板可以直接在浏览器中打开,方便前端人员查看静态原型。通过在HTML标签中添加扩展属性(如`th:text`),Thymeleaf能够在服务运行时动态替换内容,展示数据库中的数据,同时兼容静态页面展示,为开发带来灵活性和便利性。
117 0
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于 xml 的整合
本教程介绍了基于XML的MyBatis整合方式。首先在`application.yml`中配置XML路径,如`classpath:mapper/*.xml`,然后创建`UserMapper.xml`文件定义SQL映射,包括`resultMap`和查询语句。通过设置`namespace`关联Mapper接口,实现如`getUserByName`的方法。Controller层调用Service完成测试,访问`/getUserByName/{name}`即可返回用户信息。为简化Mapper扫描,推荐在Spring Boot启动类用`@MapperScan`注解指定包路径避免逐个添加`@Mapper`
123 0
微服务——SpringBoot使用归纳——Spring Boot中的项目属性配置——少量配置信息的情形
本课主要讲解Spring Boot项目中的属性配置方法。在实际开发中,测试与生产环境的配置往往不同,因此不应将配置信息硬编码在代码中,而应使用配置文件管理,如`application.yml`。例如,在微服务架构下,可通过配置文件设置调用其他服务的地址(如订单服务端口8002),并利用`@Value`注解在代码中读取这些配置值。这种方式使项目更灵活,便于后续修改和维护。
66 0
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— application.yml 中对日志的配置
在 Spring Boot 项目中,`application.yml` 文件用于配置日志。通过 `logging.config` 指定日志配置文件(如 `logback.xml`),实现日志详细设置。`logging.level` 可定义包的日志输出级别,例如将 `com.itcodai.course03.dao` 包设为 `trace` 级别,便于开发时查看 SQL 操作。日志级别从高到低为 ERROR、WARN、INFO、DEBUG,生产环境建议调整为较高级别以减少日志量。本课程采用 yml 格式,因其层次清晰,但需注意格式要求。
244 0
Spring Boot 可视化监控
本文介绍了如何通过Spring Actuator、Micrometer、Prometheus和Grafana为Spring Boot应用程序添加监控功能。首先创建了一个Spring Boot应用,并配置了Spring Actuator以暴露健康状态和指标接口。接着,利用Micrometer收集应用性能数据,并通过Prometheus抓取这些数据进行存储。最后,使用Grafana将Prometheus中的数据可视化,展示在精美的仪表板上。整个过程简单易行,为Spring Boot应用提供了基本的监控能力,同时也为后续扩展更详细的监控指标奠定了基础。
135 2
|
4月前
|
基于SpringBoot的Redis开发实战教程
Redis在Spring Boot中的应用非常广泛,其高性能和灵活性使其成为构建高效分布式系统的理想选择。通过深入理解本文的内容,您可以更好地利用Redis的特性,为应用程序提供高效的缓存和消息处理能力。
257 79
|
4月前
|
SpringBoot自动配置原理
本文深入解析了SpringBoot的核心功能——自动配置,重点探讨了`org.springframework.boot.autoconfigure`及相关注解的工作机制。通过分析`@SpringBootApplication`、`@EnableAutoConfiguration`等注解,揭示了SpringBoot如何基于类路径和条件自动装配Bean
151 7
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 的使用
本文介绍了 Thymeleaf 在 Spring Boot 项目中的使用方法,包括访问静态页面、处理对象和 List 数据、常用标签操作等内容。通过示例代码展示了如何配置 404 和 500 错误页面,以及如何在模板中渲染对象属性和列表数据。同时总结了常用的 Thymeleaf 标签,如 `th:value`、`th:if`、`th:each` 等,并提供了官方文档链接以供进一步学习。
148 0
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 的使用
详细介绍SpringBoot启动流程及配置类解析原理
通过对 Spring Boot 启动流程及配置类解析原理的深入分析,我们可以看到 Spring Boot 在启动时的灵活性和可扩展性。理解这些机制不仅有助于开发者更好地使用 Spring Boot 进行应用开发,还能够在面对问题时,迅速定位和解决问题。希望本文能为您在 Spring Boot 开发过程中提供有效的指导和帮助。
213 12
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问