1. 引言

在构建分层架构的大型 Java 应用时,通常会涉及多种模型:持久层实体、领域模型、DTO 等。不同层级之间频繁的数据传输,必然带来对象之间的映射需求。

如果手动实现 set/get 拷贝,不仅代码冗余、开发效率低,后期维护也是一场灾难。好在生态中有不少成熟的对象映射框架,能帮我们自动完成这项工作。

本文将从性能角度,横向对比目前最主流的 5 款 Java Bean 映射框架,帮你避开踩坑,选型不纠结。


2. 主流映射框架概览

2.1. Dozer

特点:老牌框架,基于递归实现对象拷贝,支持自动类型转换(如 String ↔ Integer)。

⚠️ 缺点:运行时通过反射操作,性能较差,且配置依赖 XML。

Maven 依赖:

<dependency>
    <groupId>com.github.dozermapper</groupId>
    <artifactId>dozer-core</artifactId>
    <version>6.5.2</version>
</dependency>

更多用法参考:Dozer 官方文档


2.2. Orika

特点:与 Dozer 类似,但底层使用 字节码生成技术(如 ASM),生成真正的 Mapper 类,性能更高。

⚠️ 重大限制:当前最新版 1.5.4 在 Java 16+ 环境下会触发 illegal reflective access 错误,无法使用。社区预计 1.6.0 版本修复。

Maven 依赖:

<dependency>
    <groupId>ma.glasnost.orika</groupId>
    <artifactId>orika-core</artifactId>
    <version>1.5.4</version>
</dependency>

官方文档:Orika 官网


2.3. MapStruct

特点编译期代码生成器,在编译时自动生成实现类,无运行时反射开销,性能极佳,且类型安全。

优势:IDE 友好,支持 Lombok,报错直接定位到注解位置,调试方便。

Maven 依赖:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.6.0.Beta1</version>
</dependency>

官方文档:mapstruct.org


2.4. ModelMapper

特点:基于“约定优于配置”理念,自动推断字段映射关系,API 简洁。

⚠️ 缺点:完全依赖运行时反射,性能偏低,复杂映射需手动配置。

Maven 依赖:

<dependency>
  <groupId>org.modelmapper</groupId>
  <artifactId>modelmapper</artifactId>
  <version>3.2.0</version>
</dependency>

官方文档:modelmapper.org


2.5. JMapper

特点:支持注解、XML、API 三种配置方式,强调 DRY 原则,性能表现亮眼。

⚠️ 注意:枚举类型不能自动转换,需手动编写 @JMapConversion 方法。

Maven 依赖:

<dependency>
    <groupId>com.googlecode.jmapper-framework</groupId>
    <artifactId>jmapper-core</artifactId>
    <version>1.6.1.CR2</version>
</dependency>

官方文档:GitHub Wiki


3. 测试模型设计

为了全面评估性能,我们设计了两组测试用例:

3.1. 简单模型(Simple Model)

仅包含单一字段,用于测试基础映射性能。

public class SourceCode {
    String code;
    // getter and setter
}
public class DestinationCode {
    String code;
    // getter and setter
}

3.2. 真实业务模型(Real-Life Model)

模拟订单场景,包含嵌套对象、集合、枚举等复杂结构。

public class SourceOrder {
    private String orderFinishDate;
    private PaymentType paymentType;
    private Discount discount;
    private DeliveryData deliveryData;
    private User orderingUser;
    private List<Product> orderedProducts;
    private Shop offeringShop;
    private int orderId;
    private OrderStatus status;
    private LocalDate orderDate;
    // standard getters and setters
}
public class Order {
    private User orderingUser;
    private List<Product> orderedProducts;
    private OrderStatus orderStatus;
    private LocalDate orderDate;
    private LocalDate orderFinishDate;
    private PaymentType paymentType;
    private Discount discount;
    private int shopId;
    private DeliveryData deliveryData;
    private Shop offeringShop;
    // standard getters and setters
}

完整模型代码见 GitHub:baeldung-tutorials/model


4. 统一转换器接口

为统一测试入口,定义通用 Converter 接口:

public interface Converter {
    Order convert(SourceOrder sourceOrder);
    DestinationCode convert(SourceCode sourceCode);
}

各框架实现如下:

4.1. OrikaConverter

public class OrikaConverter implements Converter {
    private MapperFacade mapperFacade;

    public OrikaConverter() {
        MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
        mapperFactory.classMap(Order.class, SourceOrder.class)
            .field("orderStatus", "status").byDefault().register();
        mapperFacade = mapperFactory.getMapperFacade();
    }

    @Override
    public Order convert(SourceOrder sourceOrder) {
        return mapperFacade.map(sourceOrder, Order.class);
    }

    @Override
    public DestinationCode convert(SourceCode sourceCode) {
        return mapperFacade.map(sourceCode, DestinationCode.class);
    }
}

4.2. DozerConverter

需配合 dozer-mapping.xml 配置文件:

<mappings xmlns="http://dozermapper.github.io/schema/bean-mapping"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mapping
  https://dozermapper.github.io/schema/bean-mapping.xsd">

    <mapping>
        <class-a>com.baeldung.performancetests.model.source.SourceOrder</class-a>
        <class-b>com.baeldung.performancetests.model.destination.Order</class-b>
        <field>
            <a>status</a>
            <b>orderStatus</b>
        </field>
    </mapping>
    <mapping>
        <class-a>com.baeldung.performancetests.model.source.SourceCode</class-a>
        <class-b>com.baeldung.performancetests.model.destination.DestinationCode</class-b>
    </mapping>
</mappings>

Java 实现:

public class DozerConverter implements Converter {
    private final Mapper mapper;

    public DozerConverter() {
        this.mapper = DozerBeanMapperBuilder.create()
            .withMappingFiles("dozer-mapping.xml")
            .build();       
    }

    @Override
    public Order convert(SourceOrder sourceOrder) {
        return mapper.map(sourceOrder, Order.class);
    }

    @Override
    public DestinationCode convert(SourceCode sourceCode) {
        return mapper.map(sourceCode, DestinationCode.class);
    }
}

4.3. MapStructConverter

@Mapper
public interface MapStructConverter extends Converter {
    MapStructConverter MAPPER = Mappers.getMapper(MapStructConverter.class);

    @Mapping(source = "status", target = "orderStatus")
    @Override
    Order convert(SourceOrder sourceOrder);

    @Override
    DestinationCode convert(SourceCode sourceCode);
}

4.4. JMapperConverter

public class JMapperConverter implements Converter {
    JMapper realLifeMapper;
    JMapper simpleMapper;

    public JMapperConverter() {
        JMapperAPI api = new JMapperAPI()
            .add(JMapperAPI.mappedClass(Order.class));
        realLifeMapper = new JMapper(Order.class, SourceOrder.class, api);
        JMapperAPI simpleApi = new JMapperAPI()
            .add(JMapperAPI.mappedClass(DestinationCode.class));
        simpleMapper = new JMapper(DestinationCode.class, SourceCode.class, simpleApi);
    }

    @Override
    public Order convert(SourceOrder sourceOrder) {
        return (Order) realLifeMapper.getDestination(sourceOrder);
    }

    @Override
    public DestinationCode convert(SourceCode sourceCode) {
        return (DestinationCode) simpleMapper.getDestination(sourceCode);
    }
}

⚠️ 枚举转换需额外方法:

@JMapConversion(from = "paymentType", to = "paymentType")
public PaymentType conversion(com.baeldung.performancetests.model.source.PaymentType type) {
    PaymentType paymentType = null;
    switch(type) {
        case CARD:
            paymentType = PaymentType.CARD;
            break;
        case CASH:
            paymentType = PaymentType.CASH;
            break;
        case TRANSFER:
            paymentType = PaymentType.TRANSFER;
            break;
    }
    return paymentType;
}

4.5. ModelMapperConverter

public class ModelMapperConverter implements Converter {
    private ModelMapper modelMapper;

    public ModelMapperConverter() {
        modelMapper = new ModelMapper();
    }

    @Override
    public Order convert(SourceOrder sourceOrder) {
       return modelMapper.map(sourceOrder, Order.class);
    }

    @Override
    public DestinationCode convert(SourceCode sourceCode) {
        return modelMapper.map(sourceCode, DestinationCode.class);
    }
}

5. 简单模型性能测试

使用 JMH(Java Microbenchmark Harness)进行基准测试,涵盖四种模式。

5.1. 平均执行时间(AverageTime)✅ 越小越好

框架 平均耗时(ms/操作)
MapStruct ~0.00001
JMapper ~0.00001
Orika 0.001
ModelMapper 0.002
Dozer 0.004

结论:MapStruct 与 JMapper 并列第一,性能碾压其他框架。


5.2. 吞吐量(Throughput)✅ 越大越好

框架 吞吐量(操作/ms)
MapStruct 58,101
JMapper 53,667
Orika 1,195
ModelMapper 379
Dozer 230

MapStruct 略胜一筹,JMapper 紧随其后。


5.3. 单次执行时间(SingleShotTime)✅ 越小越好

框架 单次耗时(ms/操作)
JMapper 0.016
MapStruct 1.904
Dozer 3.864
Orika 6.593
ModelMapper 8.788

JMapper 表现最佳,MapStruct 因编译期生成类,首次调用略慢。


5.4. 采样时间(SampleTime)✅ 越低越好

框架 p0.90 p0.999 p1.0
JMapper 0.0001 0.001 1.526
MapStruct 0.0001 0.0001 1.948
Orika 0.001 0.018 2.327
ModelMapper 0.002 0.044 3.604
Dozer 0.003 0.088 5.382

JMapper 在极端情况下更稳定,MapStruct 次之。


6. 真实业务模型性能测试

6.1. 平均执行时间(AverageTime)

框架 平均耗时(ms/操作)
MapStruct ~0.0001
JMapper ~0.0001
Orika 0.007
ModelMapper 0.137
Dozer 0.145

MapStruct 与 JMapper 依然领跑


6.2. 吞吐量(Throughput)

框架 吞吐量(操作/ms)
MapStruct 3,467
JMapper 3,205
Orika 121
ModelMapper 7
Dozer 6.342

MapStruct 吞吐量最高,JMapper 略低但依然远超其他。


6.3. 单次执行时间(SingleShotTime)

框架 单次耗时(ms/操作)
JMapper 0.722
MapStruct 2.111
Dozer 16.311
ModelMapper 22.342
Orika 32.473

JMapper 首次调用优势明显


6.4. 采样时间(SampleTime)

框架 p0.90 p0.999 p1.0
JMapper 0.001 0.006 3
MapStruct 0.001 0.006 8
Orika 0.007 0.143 14
ModelMapper 0.138 0.991 15
Dozer 0.131 0.954 7

JMapper 在高并发、高负载下更稳定


6.5. 结论

  • JMapper 性能最强,尤其在单次和极端场景表现突出。
  • MapStruct 稳定性高,吞吐量略胜,适合高并发服务。
  • Dozer 和 ModelMapper 性能垫底,仅建议用于非核心链路或原型开发。
  • ⚠️ **Orika 受限 Java 16+**,新项目不推荐。

7. 总结

本文对 5 款主流 Java 对象映射框架进行了真实场景下的性能压测:

  • 首选推荐MapStruct —— 编译期生成,性能强、类型安全、IDE 友好,社区活跃。
  • 高性能场景JMapper —— 适合对首次调用延迟敏感的场景,但需处理枚举等细节。
  • 慎用DozerModelMapper —— 反射开销大,性能差,仅适合简单项目。
  • 观望Orika —— 待 Java 16+ 兼容版本发布。

所有测试代码已开源:GitHub - baeldung/performance-tests


原始标题:Performance of Java Mapping Frameworks | Baeldung