In daily development, we often need to assign values to objects, usually calling their set/ GET methods. Sometimes, if we want to convert two objects with roughly the same properties, we will consider using the property copy tool.

For example, we often encapsulate a data structure into DO, SDO, DTO, VO, etc., and most of the properties in these beans are the same, so using the property copy class tool can help us save a lot of set and GET operations.

There are many similar tool classes in the market, and the most common ones are

1, Spring BeanUtils

2, additional BeanCopier

3, Apache BeanUtils

4, Apache PropertyUtils

5, Dozer

So which tool class should we choose? Why is Apache BeanUtils prohibited in alibaba Java development manual?

 

Due to the gleason’s priority of space, the differences and usages of these tool classes, as well as the difference between shallow copy and deep copy, are beyond the scope of this article.

This article focuses on comparing the performance of these libraries.

The performance comparison

No Data No BB, let’s write code to compare the performance of these frameworks.

A code example is as follows:

First define a PersonDO class:

public class PersonDO { private Integer id; private String name; private Integer age; private Date birthday; // omit setter/getter}Copy the code

Define a PersonDTO class:

public class PersonDTO {
    private String name;
    private Integer age;
    private Date birthday;
}
Copy the code

Then write the test class:

Use Spring BeanUtils to copy properties:

private void mappingBySpringBeanUtils(PersonDO personDO, int times) {
    StopWatch stopwatch = new StopWatch();
    stopwatch.start();    for (int i = 0; i < times; i++) {
        PersonDTO personDTO = new PersonDTO();
        org.springframework.beans.BeanUtils.copyProperties(personDO, personDTO);    }    stopwatch.stop();    System.out.println("mappingBySpringBeanUtils cost :" + stopwatch.getTotalTimeMillis());
}
Copy the code

StopWatch is used to record the code execution time for easy comparison.

Copy attributes using Cglib BeanCopier:

private void mappingByCglibBeanCopier(PersonDO personDO, int times) {
    StopWatch stopwatch = new StopWatch();
    stopwatch.start();    for (int i = 0; i < times; i++) {
        PersonDTO personDTO = new PersonDTO();
        BeanCopier copier = BeanCopier.create(PersonDO.class, PersonDTO.class, false);
        copier.copy(personDO, personDTO, null);
    }    stopwatch.stop();    System.out.println("mappingByCglibBeanCopier cost :" + stopwatch.getTotalTimeMillis());
}
Copy the code

Copy attributes using Apache BeanUtils:

private void mappingByApacheBeanUtils(PersonDO personDO, int times)
    throws InvocationTargetException, IllegalAccessException {
    StopWatch stopwatch = new StopWatch();
    stopwatch.start();    for (int i = 0; i < times; i++) {
        PersonDTO personDTO = new PersonDTO();
        BeanUtils.copyProperties(personDTO, personDO);    }    stopwatch.stop();    System.out.println("mappingByApacheBeanUtils cost :" + stopwatch.getTotalTimeMillis());
}
Copy the code

Copy properties using Apache PropertyUtils:

private void mappingByApachePropertyUtils(PersonDO personDO, int times)
    throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
    StopWatch stopwatch = new StopWatch();
    stopwatch.start();    for (int i = 0; i < times; i++) {
        PersonDTO personDTO = new PersonDTO();
        PropertyUtils.copyProperties(personDTO, personDO);    }    stopwatch.stop();    System.out.println("mappingByApachePropertyUtils cost :" + stopwatch.getTotalTimeMillis());
}
Copy the code

Then execute the following code:

public static void main(String[] args)
    throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
    PersonDO personDO = new PersonDO();
    personDO.setName("Hollis");
    personDO.setAge(26);
    personDO.setBirthday(new Date());
    personDO.setId(1);
    MapperTest mapperTest = new MapperTest();
    mapperTest.mappingBySpringBeanUtils(personDO, 100);
    mapperTest.mappingBySpringBeanUtils(personDO, 1000);
    mapperTest.mappingBySpringBeanUtils(personDO, 10000);
    mapperTest.mappingBySpringBeanUtils(personDO, 100000);
    mapperTest.mappingBySpringBeanUtils(personDO, 1000000);
    mapperTest.mappingByCglibBeanCopier(personDO, 100);
    mapperTest.mappingByCglibBeanCopier(personDO, 1000);
    mapperTest.mappingByCglibBeanCopier(personDO, 10000);
    mapperTest.mappingByCglibBeanCopier(personDO, 100000);
    mapperTest.mappingByCglibBeanCopier(personDO, 1000000);
    mapperTest.mappingByApachePropertyUtils(personDO, 100);
    mapperTest.mappingByApachePropertyUtils(personDO, 1000);
    mapperTest.mappingByApachePropertyUtils(personDO, 10000);
    mapperTest.mappingByApachePropertyUtils(personDO, 100000);
    mapperTest.mappingByApachePropertyUtils(personDO, 1000000);
    mapperTest.mappingByApacheBeanUtils(personDO, 100);
    mapperTest.mappingByApacheBeanUtils(personDO, 1000);
    mapperTest.mappingByApacheBeanUtils(personDO, 10000);
    mapperTest.mappingByApacheBeanUtils(personDO, 100000);
    mapperTest.mappingByApacheBeanUtils(personDO, 1000000);
}
Copy the code

The results are as follows:

 

I drew a line chart so you can compare it

 

In summary, we can basically conclude that Spring BeanUtils and Cglib BeanCopier perform well in terms of performance, while Apache PropertyUtils, Apache BeanUtils and Dozer perform poorly.

Therefore, it is not recommended to choose Apache PropertyUtils, Apache BeanUtils, and Dozer utility classes for performance reasons.

Many people will not understand, why the famous Apache open source class library performance is not high? That’s not Apache style. What’s behind this poor performance?

In fact, because Apache BeanUtils is trying to be perfect, it adds a lot of validation, compatibility, log printing, and so on to the code, excessive wrapping leads to serious performance degradation.

conclusion

By comparing several common attribute copy libraries, this paper analyzes the performance of these tool classes, and finally verifies the fact of “Low efficiency of Apache BeanUtils” mentioned in “Alibaba Java Development Manual”.

However, this paper only compares a tool class from a single perspective of performance. When we choose a tool class, we also have other considerations, such as cost, difficulty of understanding, compatibility, scalability, etc. For such a copy of the tool class, we will also consider whether its function is perfect, etc.

For example, although Dozer has poor performance, it can be well integrated with Spring, and can be mapped between properties through configuration files, etc., which is also loved by many developers.

The maven dependencies for the third-party libraries used in this article are as follows:

<! <dependency> <groupId> Commons - BeanUtils </groupId> < artifactId > Commons beanutils - < / artifactId > < version > 1.9.4 < / version > < / dependency > < the dependency > <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.2</version> </dependency> <! --Spring PropertyUtils--> <dependency> <groupId>org.springframework</groupId> < artifactId > org. Springframework. Beans < / artifactId > < version > 3.1.1. RELEASE < / version > < / dependency > <! --cglib--> <dependency> <groupId>cglib</groupId> <artifactId>cglib-nodep</artifactId> <version>2.2.2</version> </dependency> <! --dozer--> <dependency> <groupId>net.sf.dozer</groupId> <artifactId>dozer</artifactId> <version>5.5.1</version> </dependency> <! Slf4j </groupId> <artifactId> slf4J-api </artifactId> <version>1.7.7</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jul-to-slf4j</artifactId> <version>1.7.7</version> </dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.7</version>  </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>1.7.7</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId> The < version > 1.7.7 < / version > < / dependency >Copy the code