微服务架构大成以来,业界持续有声音在质疑微服务架构的弊病,时不时的有曝出某某大厂回归了单体架构。今年(即2023年)5月份,又曝出亚马逊一团队抛弃微服务架构回归单体架构后,成本降低90%,引发业内热议。正于此时Spring Modulith更新到了0.6版本。
这个孵化于Moduliths项目并且现已纳入Spring Boot 体系的框架的愿景是要将单体架构的框架水平拉升到微服务架构Spring Cloud的层次,让架构师们在做架构选择的时候,能基于真正需求去考量,而不是基于框架先进性。

抛开微服务的优点先不说,我所在的公司也在成本上苦微服务架构久矣……因此,我抽空通读了官方的简介、文档和相关示例代码,以期能盼来解药,结果只能说还差点意思……
大家怀念单体架构主要是因为单体架构开发方便,部署方便,然后性能高,但是带来的缺点是事实上的紧耦合,无论再好的规范和设计,也都会随着成员的增多、时间的流逝、紧急需求的响应,导致代码纠缠不清,一团乱麻;而微服务架构带来的是松耦合,独立发布,水平扩展,但是会导致部署架构复杂,基础设施成本、运维成本飙升……
Spring Modulith的解法是用单体架构,通过规范、显式化包与包之间的调用和依赖关系,从而降低单体架构的耦合程度。提供的方法是两种:

  • 通过API方式,即由子包去主动暴露API,没有暴露的类或方法均是无法被其他包调用。具体来说,对于子包下的类和方法是默认暴露的,子包下的子包的类和方法是默认隐藏的。即使对于子包下的类和方法也可以通过增加一个package-info.java,并使用@ApplicationModule指明能被谁调用
    @org.springframework.modulith.ApplicationModule( allowedDependencies = "order" ) package example.inventory;
  • 通过事件方式,即引入一个ApplicationEventPublisher组件,子包与子包之间通过发布事件、响应事件来完成一次系统。这个过程种可以通过数据库去做事件日志的持久化,再配合事件状态检查和重传机制确保事务最终一致性。
    // 这是发布事件的核心代码,位于Order Package中
    @Service
    @RequiredArgsConstructor
    public class OrderManagement {

    private final @NonNull ApplicationEventPublisher events;
    private final @NonNull OrderInternal dependency;

    @Transactional
    public void complete(Order order) {
    events.publishEvent(new OrderCompleted(order.getId()));
    }
    }
    // 这是响应事件的核心代码,位于 Inventory Package中
    @Service
    @RequiredArgsConstructor
    class InventoryManagement {

    private static final Logger LOG = LoggerFactory.getLogger(InventoryManagement.class);

    private final InventoryInternal dependency;

    @ApplicationModuleListener
    void on(OrderCompleted event) throws InterruptedException {

    var orderId = event.orderId();

    LOG.info("Received order completion for {}.", orderId);

    // Simulate busy work
    Thread.sleep(1000);

    LOG.info("Finished order completion for {}.", orderId);
    }
    }
    除此之外,Spring Modulith还提供一些增强功能,比如spring-modulith-moments模块提供定时周期性的发布事件的能力,以及在集成测试时的mock支持、UML的自动生成还有一些监控工具等等。
    Spring Modulith会是一剂解药吗?Spring Modulith在降低模块间的耦合上的确能起到作用,但是由此也带来了额外的性能开销,而且并没有解决针对单模块的启停及扩展。Spring Cloud用RPC/HTTP来解决耦合和扩展,Spring Modulith用事件来解决耦合但未能解决扩展,但回头看Java 9 时即推出的JPMS到现在仍用者寥寥,我觉得Spring Modulith还得有一个大的提升才能有用武之地,不过现在才0.6,一切都还早……