Java常见bean mapper的性能及原理分析

背景

在分层的代码架构中,层与层之间的对象避免不了要做很多转换、赋值等操作,这些操作重复且繁琐,于是乎催生出很多工具来优雅,高效地完成这个操作,有BeanUtils、BeanCopier、Dozer、Orika等等,本文将讲述上面几个工具的使用、性能对比及原理分析。

性能分析

其实这几个工具要做的事情很简单,而且在使用上也是类似的,所以我觉得先给大家看看性能分析的对比结果,让大家有一个大概的认识。我是使用JMH来做性能分析的,代码如下:

要复制的对象比较简单,包含了一些基本类型;有一次warmup,因为一些工具是需要“预编译”和做缓存的,这样做对比才会比较客观;分别复制1000、10000、100000个对象,这是比较常用数量级了吧。

@BenchmarkMode(Mode.AverageTime)  @OutputTimeUnit(TimeUnit.MICROSECONDS)  @Fork(1)  @Warmup(iterations = 1)  @State(Scope.Benchmark)  public class BeanMapperBenchmark {        @Param({"1000", "10000", "100000"})      private int times;        private int time;        private static MapperFactory mapperFactory;        private static Mapper mapper;        static {          mapperFactory = new DefaultMapperFactory.Builder().build();          mapperFactory.classMap(SourceVO.class, TargetVO.class)                  .byDefault()                  .register();            mapper = DozerBeanMapperBuilder.create()                  .withMappingBuilder(new BeanMappingBuilder() {                      @Override                      protected void configure() {                          mapping(SourceVO.class, TargetVO.class)                                  .fields("fullName", "name")                                  .exclude("in");                      }                  }).build();      }        public static void main(String[] args) throws Exception {          Options options = new OptionsBuilder()                  .include(BeanMapperBenchmark.class.getName()).measurementIterations(3)                  .build();          new Runner(options).run();      }        @Setup      public void prepare() {          this.time = times;      }        @Benchmark      public void springBeanUtilTest(){          SourceVO sourceVO = getSourceVO();          for(int i = 0; i < time; i++){              TargetVO targetVO = new TargetVO();              BeanUtils.copyProperties(sourceVO, targetVO);          }      }        @Benchmark      public void apacheBeanUtilTest() throws Exception{          SourceVO sourceVO = getSourceVO();          for(int i = 0; i < time; i++){              TargetVO targetVO = new TargetVO();              org.apache.commons.beanutils.BeanUtils.copyProperties(targetVO, sourceVO);          }        }        @Benchmark      public void beanCopierTest(){          SourceVO sourceVO = getSourceVO();          for(int i = 0; i < time; i++){              TargetVO targetVO = new TargetVO();              BeanCopier bc = BeanCopier.create(SourceVO.class, TargetVO.class, false);              bc.copy(sourceVO, targetVO, null);          }        }        @Benchmark      public void dozerTest(){          SourceVO sourceVO = getSourceVO();          for(int i = 0; i < time; i++){              TargetVO map = mapper.map(sourceVO, TargetVO.class);          }      }        @Benchmark      public void orikaTest(){          SourceVO sourceVO = getSourceVO();          for(int i = 0; i < time; i++){              MapperFacade mapper = mapperFactory.getMapperFacade();              TargetVO map = mapper.map(sourceVO, TargetVO.class);          }      }        private SourceVO getSourceVO(){          SourceVO sourceVO = new SourceVO();          sourceVO.setP1(1);          sourceVO.setP2(2L);          sourceVO.setP3(new Integer(3).byteValue());          sourceVO.setDate1(new Date());          sourceVO.setPattr1("1");          sourceVO.setIn(new SourceVO.Inner(1));          sourceVO.setFullName("alben");          return sourceVO;      }    }  

在我macbook下运行后的结果如下:

image.png

图片

Score表示的是平均运行时间,单位是微秒。从执行效率来看,可以看出 beanCopier > orika > springBeanUtil > dozer > apacheBeanUtil。这样的结果跟它们各自的实现原理有很大的关系,

下面将详细每个工具的使用及实现原理。

Spring的BeanUtils

使用

这个工具可能是大家日常使用最多的,因为是Spring自带的,使用也简单:BeanUtils.copyProperties(sourceVO, targetVO);

原理

Spring BeanUtils的实现原理也比较简答,就是通过Java的Introspector获取到两个类的PropertyDescriptor,对比两个属性具有相同的名字和类型,如果是,则进行赋值(通过ReadMethod获取值,通过WriteMethod赋值),否则忽略。

为了提高性能Spring对BeanInfo和PropertyDescriptor进行了缓存。

(源码基于:org.springframework:spring-beans:4.3.9.RELEASE)

/**    * Copy the property values of the given source bean into the given target bean. 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值