Chinaunix首页 | 论坛 | 博客
  • 博客访问: 122832
  • 博文数量: 165
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1655
  • 用 户 组: 普通用户
  • 注册时间: 2022-09-26 14:37
文章分类

全部博文(165)

文章存档

2024年(2)

2023年(95)

2022年(68)

我的朋友

分类: 高性能计算

2023-01-29 10:20:42

作者:京东物流 王北永 姚再毅

1 背景

日常开发过程中,尤其在DDD过程中,经常遇到VO/MODEL/PO等领域模型的相互转换。此时我们会一个字段一个字段进行set|get设置。要么使用工具类进行暴力的属性拷贝,在这个暴力属性拷贝过程中好的工具更能提高程序的运行效率,反之引起性能低下、隐藏细节设置OOM等极端情况出现。

2 现有技术

  1. 直接set|get方法:字段少时还好,当字段非常大时工作量巨大,重复操作,费时费力。
  2. 通过反射+内省的方式实现值映射实现:比如许多开源的apache-common、spring、hutool工具类都提供了此种实现工具。这种方法的缺点就是性能低、黑盒属性拷贝。不同工具类的处理又有区别:spring的属性拷贝会忽略类型转换但不报错、hutool会自动进行类型转、有些工具设置抛出异常等等。出现生产问题,定位比较困难。
  3. mapstruct:使用前需要手动定义转换器接口,根据接口类注解和方法注解自动生成实现类,属性转换逻辑清晰,但是不同的领域对象转换还需要单独写一层转换接口或者添加一个转换方法。

3 扩展设计

3.1 mapstruct介绍

本扩展组件基于mapstruct进行扩展,简单介绍mapstruct实现原理。

mapstruct是基于JSR 269实现的,JSR 269是JDK引进的一种规范。有了它,能够实现在编译期处理注解,并且读取、修改和添加抽象语法树中的内容。JSR 269使用Annotation Processor在编译期间处理注解,Annotation Processor相当于编译器的一种插件,因此又称为插入式注解处理。

我们知道,java的类加载机制是需要通过编译期运行期。如下图所示


mapstruct正是在上面的编译期编译源码的过程中,通过修改语法树二次生成字节码,如下图所示


以上大概可以概括如下几个步骤:

1、生成抽象语法树。Java编译器对Java源码进行编译,生成抽象语法树(Abstract Syntax Tree,AST)。

2、调用实现了JSR 269 API的程序。只要程序实现了JSR 269 API,就会在编译期间调用实现的注解处理器。

3、修改抽象语法树。在实现JSR 269 API的程序中,可以修改抽象语法树,插入自己的实现逻辑。

4、生成字节码。修改完抽象语法树后,Java编译器会生成修改后的抽象语法树对应的字节码文件件。

从mapstruct实现原理来看,我们发现mapstruct属性转换逻辑清晰,具备良好的扩展性,问题是需要单独写一层转换接口或者添加一个转换方法。能否将转换接口或者方法做到自动扩展呢?

3.2 改进方案

上面所说mapstruct方案,有个弊端。就是如果有新的领域模型转换,我们不得不手动写一层转换接口,如果出现A/B两个模型互转,一般需定义四个方法:A->B、B->A、List

阅读(250) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~