SmartOrder — 第4部分:深入库存服务

发布: (2026年3月9日 GMT+8 17:54)
6 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您希望翻译的完整文本内容(除代码块和 URL 之外),我将按照要求将其翻译成简体中文并保留原有的格式。

所有权与边界

Inventory Service 拥有每个商品的库存状态——availablereservedout of stockdiscontinued。它 管理订单生命周期或定价。边界是严格的:

  • No cross‑service joins
  • No shared schemas
  • No synchronous calls

它消费 OrderCreated 事件并作出响应,使 解耦的、最终一致的微服务 —— SmartOrder 架构的基石。

领域模型与 commons 集成

@Entity
@Table
@Data
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@Jacksonized
@EntityListeners(AuditingEntityListener.class)
public class Inventory implements it.portus84.business.commons.model.Entity {

    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private UUID id;

    private String description;

    @NotNull
    @Builder.Default
    @Enumerated(EnumType.STRING)
    private InventoryStatus status = InventoryStatus.PENDING;

    @CreatedDate
    @Setter(AccessLevel.NONE)
    @Column(nullable = false, updatable = false)
    private LocalDateTime createdDate;

    @LastModifiedDate
    @Setter(AccessLevel.NONE)
    @Column(nullable = false)
    private LocalDateTime lastModifiedDate;
}
  • InventoryStatus 驱动 saga
  • @CreatedDate / @LastModifiedDate 利用 commons‑business auditing

该仓库(Repository)故意保持简洁:

public interface InventoryRepository extends JpaRepository {}

多语言持久化

  • Inventory Service 使用 Spring Data JPA 与 H2/Postgres。
  • Order Service 使用 MongoDB

为什么要混合使用?

需求选择
原子库存级别更新JPA 事务语义
预订(reserve → commit)事务保证
审计与时间戳JPA 审计(commons 集成)

Commons 模块提供 基础实体、映射器接口和助手,确保各服务之间模式一致。

事件驱动的消费

@Bean
public Consumer orderCreatedConsumer() {
    return event -> orderConfirmationPublisher.send(event);
}
spring:
  cloud:
    function:
      definition: orderCreatedConsumer
    stream:
      function:
        bindings:
          orderCreatedConsumer-in-0: consumeOrderCreated
      bindings:
        consumeOrderCreated:
          destination: pending-orders
          group: inventory-group
  • inventory-group 保证 在所有实例中对每个事件仅处理一次
  • 该消费者是 无状态纯粹事件驱动 的。

公共库提供 共享 DTO 和绑定常量

@UtilityClass
public class BindingNames {
    public static final String PUBLISH_ORDER_CONFIRMED   = "publishOrderConfirmed";
    public static final String PUBLISH_ORDER_OUT_OF_STOCK = "publishOrderOutOfStock";
}

可用性检查与条件事件发布

@Slf4j
@Component
@RequiredArgsConstructor
public class OrderConfirmationPublisher {

    private final StreamBridge streamBridge;
    private final InventoryService inventoryService;

    public void send(OrderCreatedEvent event) {
        boolean available = inventoryService.checkAvailability(event.getOrderId());
        if (available) {
            streamBridge.send(BindingNames.PUBLISH_ORDER_CONFIRMED,
                              new OrderConfirmedEvent(event.getOrderId()));
        } else {
            streamBridge.send(BindingNames.PUBLISH_ORDER_OUT_OF_STOCK,
                              new OrderOutOfStockEvent(event.getOrderId(),
                                                       "Insufficient stock"));
        }
    }
}
  • 决策逻辑是 命令式的,但通过事件实现完全解耦
  • 来自 commons 的共享 events‑model 确保序列化的一致性。
  • StreamBridge 使得输出绑定的动态选择成为可能。

HATEOAS in REST responses

@Override
public ResponseEntity> getInventoryById(UUID id) {
    return inventoryService.findById(id)
        .map(inventoryMapper::toDTO)
        .map(hateoasHelper::toEntityModel)
        .map(ResponseEntity::ok)
        .orElseThrow(() -> new InventoryNotFoundException(id));
}
  • 通过 hateoasHelper 生成的 HATEOAS 链接动态引导客户端。
  • 支持 PATCH / UPDATE 操作,无需硬编码 URI。

Commons 提供 共享的 mapper 接口、分页 mapper 和 HATEOAS 辅助工具

事件驱动工作流:已解决的挑战

  1. 订单服务 publishes OrderCreated
  2. 库存服务 consumes it。
  3. OrderConfirmationPublisher decides based on stock。
  4. Either OrderConfirmedEvent or OrderOutOfStockEvent is published。
  5. 订单服务 updates its state accordingly。

已解决的挑战

挑战解决方案
事件驱动的库存预留无分布式事务;通过事件实现最终一致性
原子可用性检查库存服务中的 JPA 事务语义
样板代码减少共享公共基础设施(实体、映射器、DTO、辅助类)

待办:checkAvailability

@Override
public boolean checkAvailability(String orderId) {
    // TODO: validate each
}

实现需要获取订单行,累计所需数量,与当前库存进行比较,并可能在单个事务中预留这些商品。

产品项目与实际库存

return true;

占位符始终返回 true

开发者的下一步

OrderCreatedEvent 中的产品行项目集成,并对每个库存记录的数量进行验证。

注意: 此 TODO 不属于本文范围,但对于完整的库存正确性至关重要。

引导和测试数据(开发者提示)

@AutoConfiguration
@ConditionalOnClass(Instancio.class)
public class TestDataLoaderConfiguration {

    @Bean
    CommandLineRunner loadTestData(InventoryService service) {
        return args -> service.saveAll(
            Instancio.ofList(Inventory.class)
                     .size(5)
                     .ignoreFields()
                     .create()
        );
    }
}
  • Instancio 为本地开发生成种子数据。
  • 确保 一致的设置,且不影响生产环境。

接下来:commons 模块

重点关注 services/commons

order-serviceinventory-service 中共享的 业务逻辑、DTO、事件定义和辅助工具

包含内容

  • 实体基类
  • MapStruct 映射器
  • HATEOAS 辅助工具
  • 测试数据加载器

Commons 是在不复制样板代码的情况下扩展 SmartOrder 的关键。

Repository:

0 浏览
Back to Blog

相关文章

阅读更多 »