PropertyUtils和BeanUtils这两个类功能基本相同。
相同点:都是浅拷贝,都提供了copyProperties()方法,只要属性名相同,类型相同 就可以从源bean 拷贝到目标bean中。PropertyUtils 和 BeanUtils 使用的是反射机制来完成属性的复制。
而BeanCopier 的原理是通过字节码动态生成一个类,这个里面实现get 和 set方法。(性能和对象直接调用set一样)
BeanCopier 唯一的花销是生成动态类上,但是生成的后的象可以自己保存起来反复使用。
BeanCopier的性能是PropertyUtils (apache-common)的500倍。 PropertyUtils的性能是BeanUtils(apache-common)的2倍。
注意:即使源类型是原始类型(int, short和char等),目标类型是其包装类型(Integer, Short和Character等),或反之:都不会被拷贝。
注:一旦使用Converter,BeanCopier只使用Converter定义的规则去拷贝属性,所以在convert方法中要考虑所有的属性。
主要的区别有:
1、PropertyUtils提供的方法多于BeanUtils提供的方法。
2、BeanUtils在对Bean赋值时会进行类型转化,BeanUtils会调用默认的转换器(Converter)进行类型转换,所以在拷贝时能对八个基本类型间进行转换,不会转换时抛出错误;PropertyUtils不会进行类型进行转化,如果类型不同则会抛出异常:[java.lang.IllegalArgumentException: argument type mismatch]。
各个copy 花费的时间区别
create object number | 1000 |
技术框架 Framework | 花费时间 time cost |
Pure get/set | 11ms |
Easy mapper | 44ms |
Cglib beancopier | 7ms |
Beanutils | 248ms |
PropertyUtils | 129ms |
Spring BeanUtils | 95ms |
Dozer | 772ms |
缓存BeanCopier提升性能
Cglib是一款比较底层的操作java字节码的框架。BeanCopier是一个工具类,可以用于Bean对象内容的复制。
BeanCopier拷贝速度快,性能瓶颈出现在创建BeanCopier实例的过程中。 所以,把创建过的BeanCopier实例放到缓存中,下次可以直接获取,提升性能。
pom.xml:
<!-- https://mvnrepository.com/artifact/com.stephenduncanjr/easymock-propertyutils -->
<dependency>
<groupId>com.stephenduncanjr</groupId>
<artifactId>easymock-propertyutils</artifactId>
<version>1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.esotericsoftware/reflectasm -->
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>reflectasm</artifactId>
<version>1.11.9</version>
</dependency>
package com.example.demo;
import com.esotericsoftware.reflectasm.ConstructorAccess;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.test.context.junit4.SpringRunner;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
/**
* @Author: 凤凰[小哥哥]
* @Date: 2019/7/2 10:17
* @Email: 15290810931@
*/
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class CopyTest {
/**
* PropertyUtils 拷贝
*/
@Test
public void propertyUtilsTest() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
UserInfo user = createData();
UserInfo2 user2 = new UserInfo2();
//PropertyUtils 拷贝
PropertyUtils.copyProperties(user2, user);
log.info("属性拷贝后的结果:{}",user2.toString());
//设置对象属性:[class ,属性名,属性值]
PropertyUtils.setSimpleProperty(user,"username","一点点");
PropertyUtils.setSimpleProperty(user,"pwd","521");
log.info("设置对象属性后的结果:{}",user.toString());
//获取对象属性:
String userName = PropertyUtils.getSimpleProperty(user,"username").toString();
log.info("获取对象属性值为:{}",userName);
//Bean 转换 Map
Map beanMap = PropertyUtils.describe(user);
log.info("Bean 转换 Map username:{},pws:{}",beanMap.get("username"),beanMap.get("pwd"));
//Map 转 Bean
Map map = new HashMap(16);
map.put("username","冷小熙");
map.put("pwd","521");
map.put("rolesList", Arrays.asList(1,"系统管理员"));
PropertyUtils.copyProperties(user,map);
log.info("Map 转换为 Bean 得到的结果:{}",user);
}
/**
* BeanUtils 拷贝
*/
@Test
public void beanUtilsTest() throws InvocationTargetException, IllegalAccessException {
UserInfo user = createData();
UserInfo2 user2 = new UserInfo2();
//BeanUtils 拷贝
BeanUtils.copyProperties(user2,user);
log.info("BeanUtils 拷贝的结果:{}",user2.toString());
}
/**
* BeanCopier 拷贝
*/
@Test
public void BeanCopierTest(){
UserInfo user = createData();
UserInfo2 user2 = new UserInfo2();
BeanCopier beanCopier = BeanCopier.create(UserInfo.class,UserInfo2.class,false);
beanCopier.copy(user,user2,null);
log.info("BeanCopier 拷贝的结果:{}",user2.toString());
}
@Test
public void reflectasm(){
ConstructorAccess<UserInfo2> accessor = ConstructorAccess.get(UserInfo2.class);
long start = System.currentTimeMillis();
for (int i = 0;i< 1000;i++){
UserInfo2 info = accessor.newInstance();
}
long tookTime = System.currentTimeMillis() - start;
System.out.println("took time: %d(ms)%n" +tookTime);
}
private UserInfo createData(){
UserInfo user = new UserInfo();
user.setId(1);
user.setUsername("凤凰小哥哥");
user.setPwd("24");
List<Roles> roles = new ArrayList(Arrays.asList(1,"系统管理员")) ;
user.setRolesList(roles);
return user;
}
}