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;
    }
}