我有 DTO 和 DOMAIN 模型:
@Data
public class CarDomain {
private String name;
private int year;
private String color;
}
和
@Data
public class CarDto {
private String name;
private int year;
private String color;
}
我有 3 个微服务 (MS) 通过 RabbitMq 相互通信。
我有包含所有 DTO 类的 models 模块
。每个 MS 都包含 models 模块
在 Maven 中。
1 MS 发送 carDto 2 MS 接收 CarDto 并转换为 Domain。为此,我可以使用几种变体:
- 使用库例如
mapstruct
:
@Mapper public interface CarMapper { CarMapper INSTANCE = Mappers.getMapper(CarMapper.class ); CarDto carToCarDto(CarDomain car); }
并使用:
CarDto carDto = CarMapper.INSTANCE.carToCarDto(carDomain);
- 创建手动映射器:
class CarMapper { public static CarDto toDto(CarDomain car) { CarDto carDto = new CarDto(); carDto.setName(car.getName()); carDto.setYear(car.getYear()); carDto.setColor(car.getColor()); } }
现在我们使用 2 个变体。因为当我们构建微服务并在 models module
中更改 DTO 模型的某些字段时,我们会在编译时出错。例如,有人在 models module
private String name;
到
private String name1;
当我们构建项目时,我们在这一行出现错误:
carDto.setName(car.getName());// getName not found becose now getName1
但是这条路很难。对于每个 dto/域模型,我们需要创建映射器并编写每个字段。在 1 个变体中,它更容易,但如果 dto 发生变化,我们会在运行时出错。
告诉我如何匹配/映射模型 dto/域的最佳方法?
最佳答案
Becouse when we build microservice and in models module some field of DTO model change we get error on compile time.
您遇到的问题通常被认为是消息版本控制。
微服务的一个关键思想是它们可以相互独立地重新部署;你应该能够在不破坏其他一切的情况下随时更改它们。为实现这一点,我们将微服务之间的耦合限制为它们共有的消息。
因此;因此,让消息架构“正确”非常重要。
在这种情况下,正确 并不意味着您在第一时间找出要发送的正确消息,而是您投入前期设计资金来了解消息如何变化以及支持哪些消息结构这些变化。
据我所知,关于该主题的最佳引用资料是 Greg Young 的书 Versioning in an Event Sourced System .
Greg 提出了使用“弱模式”来支持向前和向后兼容性的案例;基本思路是
- 字段的含义永远不会改变
- 消费者必须忽略并且必须转发它不理解的字段
- 大多数(全部?)字段应该是可选的;消费者必须为消息中缺少某些数据元素的事件做好准备。这可能意味着准备一个可接受的默认值,或替代处理。
牢记基础;你可以看看Avro的详情, Thrift , Protocol Buffers了解标准化格式的演变趋势。 Martin Kleppmann 对 Schema Evolution in Avro, Protocol Buffers, and Thrift 的讨论可能是一个很好的中间步骤。
消息规则非常重要——架构是微服务 API 的一部分。向 API 引入向后不兼容的更改会带来很多风险,不应掉以轻心。
I have models module with all DTO classes.
这可能是一个错误;这很难说。拥有一个以不向后兼容的方式例行演化的共同核心当然是错误的。这种习惯应该改变。
关于java - 映射 dto/域以在微服务之间传输的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44996290/