1 Star 3 Fork 2

say意 / bean-copy-demo

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

bean copy 组件对比

复制组件的使用简介,以及性能对比。

一篇对比文档:https://chowdera.com/2021/07/20210713181420426x.html#

baeldung文档:https://www.baeldung.com/java-performance-mapping-frameworks

orika

官方文档:https://orika-mapper.github.io/orika-docs/intro.html

baeldung:https://www.baeldung.com/orika-mapping

orika

  • 通过字节码生成技术来进行类的属性复制,因此性能很好
  • 同时提供了非常灵活的映射配置,不同名称、不同类型的映射
  • 支持深度拷贝

允许进行的配置:

  • 指定类的映射配置
    • 整个类完全自定义转换
    • 字段转换
      • 非同名字段映射配置
      • List映射字段
      • Map映射字段
      • 内部类映射字段
      • 单向映射
      • 排除映射
    • 空值:是否进行映射处理
  • 全局不同字段类型转换
    • 全局级别
    • 字段级别

映射配置文档:https://orika-mapper.github.io/orika-docs/mappings-via-classmapbuilder.html

自定义类型转换器:https://orika-mapper.github.io/orika-docs/converters.html

orika提供了两种获取复制组件的方法,前者性能更好,后者更加通用

两种映射组件都可以反复使用

BoundMapperFacade<Source, Dest> bound = mapperFactory.getMapperFacade(Source.class, Dest.class);
MapperFacade mapper = mapperFactory.getMapperFacade();

基本使用:如果简单使用,不进行复杂的映射配置,直接获取MapperFacade就可以,不用去进行classMap的注册。

package com.sayyi.demo.bean.copy.orika;

import com.sayyi.demo.bean.domain.Dest;
import com.sayyi.demo.bean.domain.Source;
import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.impl.DefaultMapperFactory;

/**
 * @author xuchuang
 * date 2021/12/20 11:11 AM
 */
public class OrikaDemo {

    public static final DefaultMapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();

    public static void main(String[] args) {
        // 这个过程创建了一个 ClassMapBuilder 实例,进行特定类的映射配置,然后将其注册到 MapperFactory 中
        // 这里可以配置映射关系、转换器等
        mapperFactory.classMap(Source.class, Dest.class)
                // 配置自定义的自动映射关系
                .field("name", "name")
                // 其余字段使用默认映射关系
                .byDefault()
                // 将映射信息注册到 MapperFactory 中。
                .register();

        // 获取转换组件。线程安全组件
        final MapperFacade mapperFacade = mapperFactory.getMapperFacade();

        Source source = new Source();
        source.setName("aCai");
        source.setAge(21);
        final Dest dest = mapperFacade.map(source, Dest.class);
        System.out.println(dest);
    }
}

cglib

  • 和手写性能差不多
  • 只能复制相同名称、相同类型的字段

基本使用:需要自己缓存对应的BeanCopier对象,避免每次都重新生成

package com.sayyi.demo.bean.copy.cglib;

import com.sayyi.demo.bean.copy.ParentDemo;
import com.sayyi.demo.bean.domain.Dest;
import com.sayyi.demo.bean.domain.Source;
import net.sf.cglib.beans.BeanCopier;

/**
 * @author xuchuang
 * date 2021/12/20 2:39 PM
 */
public class CglibDemo {

    public static void main(String[] args) {
        final Source source = ParentDemo.genSource();
        final BeanCopier beanCopier = BeanCopier.create(Source.class, Dest.class, false);

        Dest dest = new Dest();
        beanCopier.copy(source, dest, null);
        System.out.println(dest);
    }
}

mapstruct

官方网站:https://mapstruct.org/

  • 通过接口注解,生成getset的转换代码
  • 性能接近手写
  • 可以进行灵活的转换配置
    • 不同于orika,mapstruct可以为两个类型设置多种映射关系,更加灵活
  • 支持深度拷贝
  • 需要配置maven compile插件,会导致与lombok、jmh的冲突

plugin config

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.1</version>
                    <configuration>
                        <!-- 使用mapstruct必须配置这个东西;这个如果配置了,就需要同时配置lombok、jmh等 -->
                        <annotationProcessorPaths>
                            <path>
                                <groupId>org.mapstruct</groupId>
                                <artifactId>mapstruct-processor</artifactId>
                                <version>${org.mapstruct.version}</version>
                            </path>
                            <path>
                                <groupId>org.projectlombok</groupId>
                                <artifactId>lombok</artifactId>
                                <version>${lombok.version}</version>
                            </path>
                            <path>
                                <groupId>org.openjdk.jmh</groupId>
                                <artifactId>jmh-generator-annprocess</artifactId>
                                <version>${jmh.version}</version>
                            </path>
                        </annotationProcessorPaths>
                    </configuration>
                </plugin>

使用:

声明转换接口

@Mapper
public interface SourceMapper {

    SourceMapper INSTANCE = Mappers.getMapper(SourceMapper.class);

    Dest sourceToDest(Source source);
}

调用转换逻辑

        Source source = ParentDemo.genSource();
        final Dest dest = SourceMapper.INSTANCE.sourceToDest(source);
        System.out.println(dest);

JMH测试结果

# JMH version: 1.33
# VM version: JDK 1.8.0_292, OpenJDK 64-Bit Server VM, 25.292-b10
# VM invoker: /Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/bin/java
# VM options: -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=57882:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8
# Blackhole mode: full + dont-inline hint (default, use -Djmh.blackhole.autoDetect=true to auto-detect)
# Warmup: 1 iterations, 5 s each
# Measurement: 3 iterations, 5 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.sayyi.demo.bean.copy.jmh.BeanCopyJmh.cglib

# Run progress: 0.00% complete, ETA 00:01:40
# Fork: 1 of 1
# Warmup Iteration   1: 7.032 ns/op
Iteration   1: 6.567 ns/op
Iteration   2: 6.172 ns/op
Iteration   3: 6.169 ns/op


Result "com.sayyi.demo.bean.copy.jmh.BeanCopyJmh.cglib":
  6.303 ±(99.9%) 4.177 ns/op [Average]
  (min, avg, max) = (6.169, 6.303, 6.567), stdev = 0.229
  CI (99.9%): [2.125, 10.480] (assumes normal distribution)


# JMH version: 1.33
# VM version: JDK 1.8.0_292, OpenJDK 64-Bit Server VM, 25.292-b10
# VM invoker: /Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/bin/java
# VM options: -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=57882:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8
# Blackhole mode: full + dont-inline hint (default, use -Djmh.blackhole.autoDetect=true to auto-detect)
# Warmup: 1 iterations, 5 s each
# Measurement: 3 iterations, 5 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.sayyi.demo.bean.copy.jmh.BeanCopyJmh.classMap

# Run progress: 20.00% complete, ETA 00:01:23
# Fork: 1 of 1
# Warmup Iteration   1: 80.834 ns/op
Iteration   1: 160.969 ns/op
Iteration   2: 166.946 ns/op
Iteration   3: 167.017 ns/op


Result "com.sayyi.demo.bean.copy.jmh.BeanCopyJmh.classMap":
  164.977 ±(99.9%) 63.338 ns/op [Average]
  (min, avg, max) = (160.969, 164.977, 167.017), stdev = 3.472
  CI (99.9%): [101.639, 228.316] (assumes normal distribution)


# JMH version: 1.33
# VM version: JDK 1.8.0_292, OpenJDK 64-Bit Server VM, 25.292-b10
# VM invoker: /Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/bin/java
# VM options: -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=57882:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8
# Blackhole mode: full + dont-inline hint (default, use -Djmh.blackhole.autoDetect=true to auto-detect)
# Warmup: 1 iterations, 5 s each
# Measurement: 3 iterations, 5 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.sayyi.demo.bean.copy.jmh.BeanCopyJmh.manual

# Run progress: 40.00% complete, ETA 00:01:02
# Fork: 1 of 1
# Warmup Iteration   1: 1.808 ns/op
Iteration   1: 11.603 ns/op
Iteration   2: 11.154 ns/op
Iteration   3: 11.147 ns/op


Result "com.sayyi.demo.bean.copy.jmh.BeanCopyJmh.manual":
  11.301 ±(99.9%) 4.761 ns/op [Average]
  (min, avg, max) = (11.147, 11.301, 11.603), stdev = 0.261
  CI (99.9%): [6.540, 16.063] (assumes normal distribution)


# JMH version: 1.33
# VM version: JDK 1.8.0_292, OpenJDK 64-Bit Server VM, 25.292-b10
# VM invoker: /Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/bin/java
# VM options: -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=57882:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8
# Blackhole mode: full + dont-inline hint (default, use -Djmh.blackhole.autoDetect=true to auto-detect)
# Warmup: 1 iterations, 5 s each
# Measurement: 3 iterations, 5 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.sayyi.demo.bean.copy.jmh.BeanCopyJmh.mapper

# Run progress: 60.00% complete, ETA 00:00:41
# Fork: 1 of 1
# Warmup Iteration   1: 354.183 ns/op
Iteration   1: 361.970 ns/op
Iteration   2: 363.543 ns/op
Iteration   3: 365.491 ns/op


Result "com.sayyi.demo.bean.copy.jmh.BeanCopyJmh.mapper":
  363.668 ±(99.9%) 32.182 ns/op [Average]
  (min, avg, max) = (361.970, 363.668, 365.491), stdev = 1.764
  CI (99.9%): [331.486, 395.850] (assumes normal distribution)


# JMH version: 1.33
# VM version: JDK 1.8.0_292, OpenJDK 64-Bit Server VM, 25.292-b10
# VM invoker: /Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/bin/java
# VM options: -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=57882:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8
# Blackhole mode: full + dont-inline hint (default, use -Djmh.blackhole.autoDetect=true to auto-detect)
# Warmup: 1 iterations, 5 s each
# Measurement: 3 iterations, 5 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.sayyi.demo.bean.copy.jmh.BeanCopyJmh.mapstruct

# Run progress: 80.00% complete, ETA 00:00:20
# Fork: 1 of 1
# Warmup Iteration   1: 3.849 ns/op
Iteration   1: 13.459 ns/op
Iteration   2: 12.571 ns/op
Iteration   3: 12.720 ns/op


Result "com.sayyi.demo.bean.copy.jmh.BeanCopyJmh.mapstruct":
  12.917 ±(99.9%) 8.682 ns/op [Average]
  (min, avg, max) = (12.571, 12.917, 13.459), stdev = 0.476
  CI (99.9%): [4.235, 21.599] (assumes normal distribution)


# Run complete. Total time: 00:01:44

REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
experiments, perform baseline and negative tests that provide experimental control, make sure
the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
Do not assume the numbers tell you what you want them to tell.

Benchmark              Mode  Cnt    Score    Error  Units
BeanCopyJmh.cglib      avgt    3    6.303 ±  4.177  ns/op
BeanCopyJmh.classMap   avgt    3  164.977 ± 63.338  ns/op
BeanCopyJmh.manual     avgt    3   11.301 ±  4.761  ns/op
BeanCopyJmh.mapper     avgt    3  363.668 ± 32.182  ns/op
BeanCopyJmh.mapstruct  avgt    3   12.917 ±  8.682  ns/op

空文件

简介

orika、cglib、mapstruct 类拷贝示例及性能对比 展开 收起
Java
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/sayYi/bean-copy-demo.git
git@gitee.com:sayYi/bean-copy-demo.git
sayYi
bean-copy-demo
bean-copy-demo
master

搜索帮助