选择Cglib的BeanCopier进行Bean拷贝的理由是,
其性能要比Spring的BeanUtils,Apache的BeanUtils和PropertyUtils要好很多,
尤其是数据量比较大的情况下。
- BeanCopier的主要作用是将数据库层面的Entity转化成service层的POJO。
BeanCopier
其实已经有很多开源版本,例如DozerMapper、Apache BeanUtils、Spring、Jodd BeanUtils甚至是Cglib都提供了这样的功能。我们这里讲的BeanCopier来自net.sf.cglib.BeanCopier包,cglib是一款比较底层的操作java字节码的框架。 而其他多数都是基于 反射 来实现的 对象复制,所以更底层的字节码方式获取数据赋值,效率会更高 - 顾名思义,BeanCopier是用于在两个bean之间进行属性拷贝的。BeanCopier支持两种方式,一种是不使用Converter的方式,仅对两个bean间属性名和类型完全相同的变量进行拷贝。另一种则引入Converter,可以对某些特定属性值进行特殊操作。
简单用例
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.core.Converter;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import static org.junit.jupiter.api.Assertions.*;
class BeanCopyUtilsTest {
/**
* 测试说明: 类型不同BeanCopier不会拷贝
*/
@Test
void copy() {
User user = new User();
user.setId(1);
user.setName("dearth");
BeanCopier copier = BeanCopier.create(User.class, UserVo.class, false);
UserVo userVo = new UserVo();
copier.copy(user, userVo, null);
Assertions.assertNull(userVo.getId());
}
/**
* 测试说明: 提供转换器可以实现不同类型的拷贝
*/
@Test
void copyUseConverter() {
User user = new User();
user.setId(1);
user.setName("dearth");
user.setCreateTime(new Timestamp(10043143243L));
user.setBalance(BigDecimal.valueOf(4000L));
BeanCopier copier = BeanCopier.create(User.class, UserVo.class, true);
UserVo vo = new UserVo();
copier.copy(user, vo, new UserConverter());
Assertions.assertNotNull(vo.getCreateTime());
Assertions.assertNotNull(vo.getBalance());
}
@Data
@NoArgsConstructor
@AllArgsConstructor
static
class User {
private String name;
private int id;
private Timestamp createTime;
private BigDecimal balance;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
static
class UserVo {
private String name;
private Integer id;
private String createTime;
private String balance;
}
static class UserConverter implements Converter {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public Object convert(Object o, Class aClass, Object o1) {
if (o instanceof Integer) {
return (Integer) o;
} else if (o instanceof Timestamp) {
Timestamp data = (Timestamp) o;
return sdf.format(data);
} else if (o instanceof BigDecimal) {
BigDecimal bg = (BigDecimal) o;
return bg.toPlainString();
} else {
return null;
}
}
}
}
- BeanCopier只拷贝名称和类型都相同的属性。
- 当目标类的setter数目比getter少时,创建BeanCopier会失败而导致拷贝不成功。
- 自定义Converter转换器可以转换不同类型的属性