BeanUtils 简述

在 Spring 项目里,开发者经常会在 "把数据从一个对象拷贝到另一个对象" 的场景下碰到 BeanUtils 这个工具类。Spring 生态里其实有两套名字相同但实现不同的 BeanUtils

  1. Spring 自带的 org.springframework.beans.BeanUtils
  2. Apache Commons BeanUtils (org.apache.commons.beanutils.BeanUtils)

日常 Spring 项目里最常见的是 Spring 自带的版本,以下也是介绍此版本。

一、Spring 的 BeanUtils 能做什么?

常见方法 作用 备注
copyProperties(Object source, Object target) 把源对象的同名同类型属性拷贝到目标对象 最常用的方法
copyProperties(Object source, Object target, Class<?> editable) 同上,但只拷贝 editable 类里声明的属性 可做白名单
copyProperties(Object source, Object target, String... ignoreProperties) 同上,但忽略指定属性 可做黑名单
instantiateClass(Class<T> clazz) 用无参构造器实例化类 内部帮你处理了异常
findMethod(...)/getPropertyDescriptor(...) 反射工具 框架内部用得多

使用时的代码示例:

java 复制代码
import org.springframework.beans.BeanUtils;

@Data
class Source {
    private Long id;
    private String name;
    private List<String> tags;
}

@Data
class Target {
    private Long id;
    private String name;
    private List<String> tags;
}

public class Demo1 {
    public static void main(String[] args) {
        Source src = new Source();
        src.setId(1L);
        src.setName("Tom");
        src.setTags(Arrays.asList("java", "spring"));

        Target tar = new Target();
        
        // 方法一
        BeanUtils.copyProperties(src, tar);   // ← 关键一行
        System.out.println(tar);
        // Target(id=1, name=Tom, tags=[java, spring])
        
        // 方法二
        BeanUtils.copyProperties(src, tar, "id", "tags"); // id、tags 不会被拷贝
        
        // 方法三(省略了父类 / 接口声明的白名单)
        BeanUtils.copyProperties(src, tar, Base.class); // 只拷贝 Base 中声明的字段
    }
}

二、常见陷阱和建议

1、小心浅拷贝

BeanUtils.copyProperties 只复制了字段值,集合 / 数组里的元素仍然是同一引用

java 复制代码
List<Order> orders = new ArrayList<>();
source.setOrders(orders);
BeanUtils.copyProperties(source, target); // target.orders 与 source.orders 指向同一对象

2、不会触发 setter / getter 里的业务逻辑

BeanUtils.copyProperties 基于反射 + 缓存,性能较快,但也因为直接用反射写字段,任何 setter 里的校验、计算都会被跳过。

3、字段名 / 类型必须完全一致

一个字母的大小写不同或类型不兼容就拷不过去,也不会报错,只是值为 null。

三、什么是反射?

反射(Reflection)是 Java 在运行时动态加载类、探查类结构(字段、方法、构造器),并对其进行实例化、调用或赋值的机制。

你可以把"反射"想象成 Java 语言的"后门":正常情况下,你只能通过 new 或调用公开方法去使用一个类;有了反射,你就可以在运行时"拆开"类、对象、方法、字段,随意查看甚至修改,哪怕它们是 private 的。

java 复制代码
// 正常写法
Dog dog = new Dog();
dog.setName("旺财");

// 反射写法(等价功能)
Class<?> clazz = Class.forName("com.xxx.Dog");             // 1. 运行时把类加载进来
Object dog = clazz.getDeclaredConstructor().newInstance(); // 2. 创建对象
Method setName = clazz.getMethod("setName", String.class); // 3. 拿方法
setName.invoke(dog, "旺财");                               // 4. 调用方法

总结,反射就是运行时"透视"并操控 Java 类的超能力,框架靠它实现"零配置"和"动态扩展",代价是性能略慢、破坏封装,需要谨慎使用。

四、考虑包含 null 的情形

如果 srouce 或 target 本身为 null,Spring 的 BeanUtils.copyProperties 会立即抛出 IllegalArgumentException,拷贝动作根本不会发生。

java 复制代码
// 源码
public static void copyProperties(Object source, Object target, @Nullable Class<?> editable, @Nullable String... ignoreProperties) {
    Assert.notNull(source, "Source must not be null");
    Assert.notNull(target, "Target must not be null");
    ...
}

如果源对象的字段本身就是 null,那么目标字段一定会被覆写成 null(或基本类型的默认值),不会保留原值,也不会报错。

相关推荐
hqxstudying1 小时前
J2EE模式---前端控制器模式
java·前端·设计模式·java-ee·状态模式·代码规范·前端控制器模式
ZeroToOneDev4 小时前
Java(LinkedList和ArrayList底层分析)
java·开发语言
没有bug.的程序员5 小时前
JAVA面试宝典 -《 架构演进:从单体到 Service Mesh》
java·面试·架构
典学长编程5 小时前
Java从入门到精通!第十一天(Java常见的数据结构)
java·开发语言·数据结构
皮皮林5516 小时前
设计一个多租户 SaaS 系统,如何实现租户数据隔离与资源配额控制?
java·saas
霍格沃兹软件测试开发6 小时前
Playwright 自动化测试系列(6)| 第三阶段:测试框架集成指南:参数化测试 + 多浏览器并行执行
java·数据库·mysql·自动化
Bonnie_12156 小时前
02-netty基础-java四种IO模型
java·开发语言·nio·jetty
我不是星海6 小时前
建造者设计模式
java·开发语言
JIngJaneIL7 小时前
健身管理小程序|基于微信开发健身管理小程序的系统设计与实现(源码+数据库+文档)
java·数据库·小程序·论文·课程设计·毕设·健身管理小程序
Dcs7 小时前
Spring Framework 6.2 正式发布:开发者最值得关注的更新全览!
java