性能优化 ---- 避免使用 BeanUtils copy

Posted wenniuwuren

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了性能优化 ---- 避免使用 BeanUtils copy相关的知识,希望对你有一定的参考价值。

一、背景

在开发过程中,我们经常会遇到对象的转换,比如外部的 DTO 对象转换为内部的 DO 对象,这里面很多字段名都是相等的,要是一个一个去 get/set 很多人会觉得很烦,于是为了方便和代码的简介大家不约而同地找到了 UtilsBean.copy 相关的对象属性copy工具包。

当我们系统还只是 QPS 几十上百时,可能我们对系统的性能优化还不用到这么细致,当我们的系统 QPS/TPS 达到几十万上百万的时候,UtilsBean.copy 的开销问题就会凸显。

 

二、Apache、Spring、CGLib、Getter/Setter 属性copy 性能对比

package test.bean.copy;



import net.sf.cglib.beans.BeanCopier;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class BeanCopyTest 


    public static void main(String[] args) throws Exception
        TargetDTO targetDTO = new TargetDTO();
        SourceDTO sourceDTO = new SourceDTO();
        sourceDTO.setAge(18);
        sourceDTO.setName("wenniuwuren");
        int totalTimes = 10000;


        /**
         * Apache BeanUtils
         */
        long startTime1 = System.currentTimeMillis();
        for (int i = 0; i < totalTimes; i++) 
            org.apache.commons.beanutils.BeanUtils.copyProperties(targetDTO, sourceDTO);
        
        System.out.println("Apache BeanUtils single thread cost:" + (System.currentTimeMillis() - startTime1) + targetDTO.getName() + targetDTO.getAge());

        ExecutorService executorService4 = Executors.newFixedThreadPool(3);
        long startTime4 = System.currentTimeMillis();
        for (int i = 0; i < totalTimes; i++) 
            executorService4.submit(new Runnable() 
                @Override
                public void run() 
                    try 
                        org.apache.commons.beanutils.BeanUtils.copyProperties(new TargetDTO(), sourceDTO);
                     catch (Exception e) 
                        e.printStackTrace();
                    
                
            );
        
        executorService4.shutdown();
        while (true) 
            if (executorService4.isTerminated()) 
                System.out.println("Apache BeanUtils muti thread cost:" + (System.currentTimeMillis() - startTime4));
                break;
            
        




        /**
         * Spring BeanUtils
         */
        targetDTO = new TargetDTO();
        long startTime2 = System.currentTimeMillis();
        for (int i = 0; i < totalTimes; i++) 
            org.springframework.beans.BeanUtils.copyProperties(sourceDTO, targetDTO);
        
        System.out.println("Spring BeanUtils single thread cost:" + (System.currentTimeMillis() - startTime2) + targetDTO.getName() + targetDTO.getAge());

        ExecutorService executorService5 = Executors.newFixedThreadPool(3);
        long startTime5 = System.currentTimeMillis();
        for (int i = 0; i < totalTimes; i++) 
            executorService5.submit(new Runnable() 
                @Override
                public void run() 
                    try 
                        org.springframework.beans.BeanUtils.copyProperties(sourceDTO, new TargetDTO());
                     catch (Exception e) 
                        e.printStackTrace();
                    
                
            );
        
        executorService5.shutdown();
        while (true) 
            if (executorService5.isTerminated()) 
                System.out.println("Spring BeanUtils muti thread cost:" + (System.currentTimeMillis() - startTime5));
                break;
            
        


        /**
         * CGLib BeanUtils
         */
        targetDTO = new TargetDTO();
        long startTime3 = System.currentTimeMillis();
        BeanCopier beanCopier = BeanCopier.create(SourceDTO.class, TargetDTO.class, false);
        for (int i = 0; i < totalTimes; i++) 
            beanCopier.copy(sourceDTO, targetDTO, null);
        
        System.out.println("CGLib BeanUtils cost:" + (System.currentTimeMillis() - startTime3) + targetDTO.getName() + targetDTO.getAge());

        ExecutorService executorService6 = Executors.newFixedThreadPool(3);
        long startTime6 = System.currentTimeMillis();
        for (int i = 0; i < totalTimes; i++) 
            executorService6.submit(new Runnable() 
                @Override
                public void run() 
                    try 
                        beanCopier.copy(sourceDTO, new TargetDTO(), null);
                     catch (Exception e) 
                        e.printStackTrace();
                    
                
            );
        
        executorService6.shutdown();
        while (true) 
            if (executorService6.isTerminated()) 
                System.out.println("CGLib BeanUtils muti thread cost:" + (System.currentTimeMillis() - startTime6));
                break;
            
        


        /**
         * Getter Setter
         */
        long startTime7 = System.currentTimeMillis();
        for (int i = 0; i < totalTimes; i++) 
            targetDTO.setAge(sourceDTO.getAge());
            targetDTO.setName(sourceDTO.getName());
        
        System.out.println("GetterSetter single thread cost:" + (System.currentTimeMillis() - startTime7) + targetDTO.getName() + targetDTO.getAge());

        ExecutorService executorService8 = Executors.newFixedThreadPool(3);
        long startTime8 = System.currentTimeMillis();
        for (int i = 0; i < totalTimes; i++) 
            executorService8.submit(new Runnable() 
                @Override
                public void run() 
                    try 
                        final TargetDTO targetDTO = new TargetDTO();
                        targetDTO.setAge(sourceDTO.getAge());
                        targetDTO.setName(sourceDTO.getName());
                     catch (Exception e) 
                        e.printStackTrace();
                    
                
            );
        
        executorService8.shutdown();
        while (true) 
            if (executorService8.isTerminated()) 
                System.out.println("GetterSetter muti thread cost:" + (System.currentTimeMillis() - startTime8));
                break;
            
        

    





 

运行结果:

Apache BeanUtils single thread cost:216nullnull
Apache BeanUtils muti thread cost:62
Spring BeanUtils single thread cost:168wenniuwuren18
Spring BeanUtils muti thread cost:18
CGLib BeanUtils cost:72wenniuwuren18
CGLib BeanUtils muti thread cost:8
GetterSetter single thread cost:0wenniuwuren18
GetterSetter muti thread cost:12

 

 

三、结论

从上述结果可以看出来,性能上 Getter/Setter > CGLib > Spring > Apache


优点
1、简洁方便,耗时短

缺点
1、性能较差,因为 BeanUtils.copy 实现是通过java反射机制
2、引用查找难,BeanUtils.copy的实现会隐藏对象属性的设置的调用,想查看target属性A有哪些地方被设值了,那么通过IDE查找引用会漏掉BeanUtils.copy的设置

 

以上是关于性能优化 ---- 避免使用 BeanUtils copy的主要内容,如果未能解决你的问题,请参考以下文章

为啥阿里代码规约要求避免使用 Apache BeanUtils 进行属性复制

Beanutils.copyProperties( )的使用与优化

java jdbc的优化之BeanUtils组件

前端性能优化:jquery性能优化

移动站点性能优化

性能优化: 避免重绘与回流的实现方式