BeanUtils简介
BeanUtils提供对Java反射和自省API的包装,其主要目的是利用反射机制对JavaBean的属性进行处理,简化JavaBean封装数据的操作。
BeanUtils工具类的实现主要包含:Apache commons包实现的BeanUtils工具类,以及spring-beans实现的BeanUtils的工具类。
为什么要使用BeanUtils
在我们实际项目开发过程中,我们经常需要将不同的两个对象实例进行属性复制,从而基于源对象的属性信息进行后续操作,而不改变源对象的属性信息。
比如DTO数据传输对象和数据对象DO,我们需要将DO对象进行属性复制到DTO,但是对象格式又不一样,所以我们需要编写映射代码将对象中的属性值从一种类型转换成另一种类型。
通常会调用其set/get方法,有些时候,但是我们很不喜欢写很多冗长的b.setF1(a.getF1())这样的代码,于是我们需要简化对象拷贝方式。
为了解决这一痛点,就诞生了一些方便的BeanUtils类库,比如:常用的有 apache的 BeanUtils,spring的 BeanUtils等拷贝工具类。
Apache 的 BeanUtils
首先来看一个非常简单的BeanUtils的例子,代码如下:
public class PersonSource { private Integer id; private String username; private String password; private Integer age; // getters/setters omiited } public class PersonDest { private Integer id; private String username; private Integer age; // getters/setters omiited } public class TestApacheBeanUtils { public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { //下面只是用于单独测试 PersonSource personSource = new PersonSource(1, "mikechen", "12345", 35); PersonDest personDest = new PersonDest(); BeanUtils.copyProperties(personDest,personSource); System.out.println("persondest: "+personDest); } } persondest: PersonDest{id=1, username='mikechen', age=35}
从上面的例子可以看出,对象拷贝非常简单,BeanUtils最常用的方法就是:
//将源对象中的值拷贝到目标对象 public static void copyProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException { BeanUtilsBean.getInstance().copyProperties(dest, orig); }
默认情况下,使用org.apache.commons.beanutils.BeanUtils对复杂对象的复制是引用,这是一种浅拷贝。
浅拷贝:对基本数据类型进行值传递,对引用数据类型,使用其引用地址,不拷贝其内容,此为浅拷贝
深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。
但是由于 Apache下的BeanUtils对象拷贝性能太差,不建议使用,而且在阿里巴巴Java开发规约插件上也明确指出,避免用Apache Beanutils进行属性的copy。
为什么《阿里巴巴Java开发手册》中提到禁止使用Apache BeanUtils呢?
深复制(深克隆)被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量,那些引用其他对象的变量将指向被复制过的新对象,而不再试原有的那些被引用的对象,换言之,深复制把要复制的对象所引用的对象都复制了一遍。
Spring的 BeanUtils
如果想用BeanUtils工具,一般会建议使用Spring BeanUtils的实现。
看一个简单的例子,使用spring的BeanUtils进行对象拷贝,代码如下:
class A{ string id; string name; string age; string sex; } class B{ string id; string name; }
假如:想把一个类A中的一些属性的值,设置到另一个类B的属性中。
方法1:new 对象,然后把值一个一个的set。
B b=new B(); A a=new A(); b.setId(a.getId()); b.setName(a.getName());
方式2:BeanUtils.copyProperties(import org.springframework.beans.BeanUtils;)
BeanUtils.copyProperties(A,B);
Spring下的BeanUtils也是使用 copyProperties方法进行拷贝,只不过它的实现方式非常简单,就是对两个对象中相同名字的属性进行简单的get/set,仅检查属性的可访问性。
注意点:A中要复制的属性,一定要和B中的属性 相同!
Spring的BeanUtils与Apache的BeanUtils区别
BeanUtils总结
以上简要的分析两种BeanUtils,因为Apache下的BeanUtils性能较差,不建议使用,可以使用 Spring的BeanUtils,或者使用其他拷贝框架,比如 cglib BeanCopier,基于javassist的Orika等,这些也是非常优秀的类库,值得去尝试。