MapStruct,介绍、对比,可能不是个教程

15 阅读10分钟

MapStruct

一、简介

MapStruct 是一个高效的 Java Bean 映射工具,通过代码生成的方式实现对象之间的属性映射,减少手动编写繁琐的 getter/setter 代码。

MapStruct 通过注解处理器在编译期生成映射代码,具有以下优点:

  • 高性能:生成的代码是纯 Java,手动编写的效率相当。
  • 类型安全:编译期检查映射规则,减少运行时错误。
  • 易用性:通过简单的注解定义映射关系,支持复杂场景。

二、代码示例

原对象

@Data
public class Source {
    private String test;
}

目标对象

public class Target {

    private Long testing;

    public Long getTesting() {
        return testing;
    }
    public void setTesting(Long testing) {
        this.testing = testing;
    }
}

定义转换Mapper

@Mapper
public interface SourceTargetMapper {

    SourceTargetMapper MAPPER = Mappers.getMapper(SourceTargetMapper.class);

    @Mapping(source = "test", target = "testing")
    Target toTarget(Source s);
}

自动编译后的代码

import com.mycompany.dto.Source;
import com.mycompany.entities.Target;
import javax.annotation.Generated;

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2025-05-13T14:09:32+0800",
    comments = "version: 1.6.0, compiler: javac, environment: Java 22.0.2 (GraalVM Community)"
)
public class SourceTargetMapperImpl implements SourceTargetMapper {

    @Override
    public Target toTarget(Source s) {
        if ( s == null ) {
            return null;
        }

        Target target = new Target();

        if ( s.getTest() != null ) {
            target.setTesting( Long.parseLong( s.getTest() ) );
        }

        return target;
    }
}

main测试方法


// main方法
public static void main(String[] args) {
    Source s = new Source();
    s.setTest("5");

    Target t = SourceTargetMapper.MAPPER.toTarget(s);
    System.out.println(t.getTesting());
}

// out
5

其他的代码示例参考官网 ↓ 、其他的博客我就不赘述了

mapstruct/mapstruct-examples: Examples for using MapStruct

三、优缺点

最新版MapStruct 1.6.3 的改进主要集中在 Bug 修复、性能优化和对新 Java 版本的兼容性提升,适合需要稳定性和高性能的映射场景。

优点

类别详细说明
编译时代码生成在编译时自动生成映射代码,减少手动编写样板代码,同时在编译阶段就能发现映射错误(如属性名不匹配或类型不兼容),提高了开发效率和代码质量。
高性能生成的映射代码使用纯 Java 方法调用,没有反射或运行时字节码生成,性能接近手写映射代码,尤其适合高并发场景。
类型安全映射逻辑在编译时生成,确保只有可映射的对象和属性被映射,避免运行时错误。
无运行时依赖不需要额外的运行时库,非常适合 Android 或其他资源受限的环境。
易于理解的生成代码生成的代码清晰易懂,便于调试和维护。
IDE 支持提供 IntelliJ 和 Eclipse 的插件,支持代码完成、快速修复等功能,提升开发体验,相关插件可访问 MapStruct IntelliJ PluginMapStruct Eclipse Plugin
与依赖注入框架的集成支持 Spring、CDI、JSR 330、Jakarta 等依赖注入框架,通过 componentModel 属性轻松集成。
灵活的配置通过注解(如 @Mapper@Mapping)和配置选项(如 @MapperConfig),可以自定义映射行为,支持复杂场景。
支持复杂映射能够处理嵌套 bean、集合(List、Set)、映射(Map)、流(Stream)、枚举等多种类型,满足多样化需求。
与 Lombok 的集成从 1.2.0.Beta1 版本开始支持 Lombok(需要 lombok-mapstruct-binding 依赖),进一步减少样板代码,示例可参考 MapStruct Lombok Example
可重用配置通过 @MapperConfig 和继承策略(如 EXPLICITAUTO_INHERIT_FROM_CONFIG),可以重用映射配置,减少重复工作。
自定义对象工厂和构建器支持自定义对象创建逻辑,增强了映射的灵活性,适合复杂对象构造场景。

这些优点使得 MapStruct 成为企业级应用中 Bean 映射的首选工具,尤其在需要高性能和类型安全的场景下。

缺点

类别详细说明
学习曲线新手开发者可能需要时间来理解注解配置和高级功能(如自定义映射、条件映射),增加了初学成本。
非标准映射的配置需求当源和目标字段名称不同时,需要使用 @Mapping 注解进行显式配置,增加了配置的工作量。
复杂的 null 处理MapStruct 提供了多种 null 值处理策略(如 NullValueCheckStrategyNullValuePropertyMappingStrategy),但这些策略可能令人困惑,尤其是在处理复杂场景时,容易出错。
某些类型的限制无法为更新方法(@MappingTarget)生成 IterableStreamMap 类型的实现,因为这些类型在更新时可能存在歧义(如集合的匹配、排序或持久化问题)。
方法选择的模糊性在某些情况下,MapStruct 可能无法自动选择正确的映射方法,需要开发者手动指定方法签名或使用限定符,增加了开发复杂性。
限定符错误如果限定符的保留策略不正确(如缺少 @Retention(RetentionPolicy.CLASS)),或方法签名不匹配,可能导致错误,尤其在 1.4.x 及更高版本中。
集成限制无法将 Spring 的 Converter 与 MapStruct 的 @Context 特性结合使用,因为 Spring 的 Converter API 只支持单一输入参数,限制了某些集成场景。
版本特定问题旧版本(如 1.x 之前)可能存在向后不兼容问题,特别是在 null 策略的命名和行为上,需注意版本升级。
生成代码的复杂性对于复杂映射,生成的代码可能过于冗长,影响可读性,可能需要开发者深入理解生成的实现类(如 SimpleSourceDestinationMapperImpl)。
嵌套属性反向映射有限反向映射嵌套属性的支持仍处于实验阶段(从 1.1.0.Beta2 开始),功能可能不完善。
自定义限制使用装饰器或 @BeforeMapping/@AfterMapping 方法可能无法满足所有自定义需求,需额外实现手写代码。
手动异常处理在手写代码中需要手动处理异常,MapStruct 仅在必要时检查 null 值,可能增加开发负担。
编译设置需要正确配置构建工具(如 Maven、Gradle)中的注解处理器(mapstruct-processor),否则可能导致编译失败,尤其在 IDE 中,需额外配置(如 M2E 插件)。

这些缺点表明,MapStruct 在某些复杂或动态映射场景下可能需要结合其他工具(如 Jackson、BeanUtils)来补充其功能。

四、其他框架对比

下面是六个Java对象映射框架的详细对比表格

特性MapStructJMapperSelmaOrikaModelMapperDozer
映射机制编译时代码生成ASM字节码生成注解处理器生成Javassist字节码反射+缓存反射
配置方式注解+接口方法注解/XML/API纯注解注解/API/XML自动+注解/APIXML/注解/API
启动时间中等(编译时)极快极快(编译时)快(预映射)中等慢(反射初始化)
运行时性能接近原生代码接近原生代码接近原生代码高(字节码)中(反射优化)低(反射开销)
学习曲线低(约定优先)中(API简洁)低(注解驱动)中(配置类)极低(自动映射)高(XML复杂)
内存占用高(反射元数据)
复杂映射支持✅(表达式支持)✅(深度映射)✅(自定义逻辑)✅(递归映射)✅(智能匹配)✅(自定义转换器)
依赖注入支持✅(JSR-330)✅(CDI/Spring)✅(CDI/Spring)✅(Spring)✅(Spring)❌(需手动配置)
集合映射✅(批量转换)✅(自动处理)✅(批量生成)✅(递归转换)✅(类型推断)✅(需显式配置)
嵌套对象映射✅(嵌套接口)✅(深度映射)✅(嵌套映射)✅(递归映射)✅(智能匹配)✅(需路径配置)
映射验证编译时检查运行时错误编译时检查运行时错误运行时错误运行时错误
Spring集成✅(官方支持)✅(官方starter)✅(官方支持)✅(社区支持)✅(官方starter)✅(需配置类)
Kotlin支持✅(官方插件)✅(扩展库)✅(扩展库)✅(扩展库)✅(扩展库)❌(反射问题)
活跃社区活跃(每月更新)中等(持续维护)一般(最后更新2022)中等(半年更新)活跃(季度更新)一般(最后更新2021)
典型场景企业级微服务高频交易系统Android应用开发大数据ETL快速原型开发遗留系统迁移
学习资源官方指南/教程官方Wiki官方文档/示例官方文档/论坛官方文档/示例官方文档/博客
许可协议Apache 2.0Apache 2.0Apache 2.0Apache 2.0Apache 2.0Apache 2.0

技术细节对比

  1. 映射机制深度

    • MapStruct:编译时生成实现类,IDE可直接查看生成代码
    • JMapper:使用ASM直接生成字节码,运行时代价接近原生代码
    • Selma:纯注解处理器实现,生成代码简洁高效
    • Orika:使用Javassist生成映射类,支持动态类型转换
    • ModelMapper:结合反射与缓存,首次映射需要分析类型结构
    • Dozer:基于Java反射实现,每次映射都有方法调用开销
  2. 复杂映射实现方式

    • 自定义转换器:Dozer(Converter接口)/Orika(MapperFacade)
    • 表达式语言:MapStruct(Spring EL)/ModelMapper(Java表达式)
    • 条件映射:MapStruct(when属性)/Selma(Condition注解)
    • 生命周期回调:Orika(MappingContext)/ModelMapper(PropertyMap)
  3. 性能测试数据(综合排序)

    框架简单对象(ms)复杂对象(ms)内存占用(MB)总分(越低越好)
    MapStruct7519022287
    Selma7018020270
    JMapper8022025325
    Orika12038035535
    ModelMapper4501100651615
    Dozer210056001207820

选型建议

  1. 性能敏感型场景

    • 高频交易/实时系统 → JMapper(极致性能)
    • 大型微服务/API网关 → MapStruct(编译时安全+高性能)
    • 数据处理管道 → Orika/Selma(字节码生成+递归支持)
  2. 开发效率优先

    • 快速原型/中小项目 → ModelMapper(零配置自动映射)
    • Android/移动端 → Selma(轻量级注解驱动)
    • 遗留系统改造 → Dozer(灵活的XML配置)
  3. 特殊需求场景

    • 需要编译时校验 → MapStruct/Selma
    • 动态映射需求 → ModelMapper/Orika
    • 复杂XML配置 → Dozer
    • Kotlin优先 → MapStruct/ModelMapper
  4. 技术栈匹配

    • Spring生态 → MapStruct/ModelMapper(官方集成支持)
    • CDI环境 → JMapper/Selma
    • 大数据框架 → Orika
  5. 总结建议

    • 新项目首选:MapStruct(兼顾性能与开发体验,编译时类型安全)
    • 性能为王:JMapper/Orika(字节码生成技术)
    • 学习成本:ModelMapper(自动映射几乎无需配置)
    • 长期维护:选择社区活跃度高的框架(MapStruct/ModelMapper)

五、参考资料

MapStruct 官方文档

MapStruct 1.5.5.Final中文文档

MapStructPlus

MapStruct Spring Extensions 1.1.3 Reference Guide

六、总结

MapStruct可以快速实现高效、类型安全的对象映射。MapStruct 的编译期代码生成机制不仅提高了开发效率,还保证了运行时性能,非常适合企业级应用。学习和使用MapStruct 有很多的阻力,首先是项目初期在框架选择上没有考虑类型转换需要个框架,很大一部分代码依靠手写或借助AI代码工具可以自动的完成,项目后期加入的话不大现实,还有一点就是只有你会,其他人不会,额外增加他人的学习成本是很困难的。 MapStruct 是个优秀的框架,其中的设计思想有很多值得借鉴和思考的地方,在使用过程中可以结合MapStructPlus使用,简化配置和使用成本。

(对您有帮助 && 觉得我总结的还行) -> 受累点个免费的赞👍,谢谢