Skip to content
bitzorcas
中EN

Concept

模块化单体:物理工程隔离、契约边界与架构守护

深入解析 BitzOrcas.Modern 模块化单体体系:Contracts/Domain/Application 物理工程划分、跨模块依赖 5 条铁律、IAppModule 编译期发现机制与 ArchUnit 架构门禁。

Last updated

模块化单体(Modular Monolith)是 BitzOrcas.Modern 的核心架构形态。它既具备单体架构的单机部署、极速开发与事务内调用的优势,又通过严格的物理项目隔离与架构门禁杜绝了传统单体代码腐化为“大泥球”的致命风险。

模块物理结构与依赖边界拓扑

BitzOrcas.Modules.Legal 模块BitzOrcas.Modules.Billing 模块只允许依赖公开契约严禁依赖内部实现严禁依赖内部切片

非法跨模块依赖 (ArchUnit 拦截)

合法跨模块调用

Billing.Application (垂直切片)

Billing.Domain (账单聚合根)

Billing.Contracts (公开契约与 DTO)

Legal.Application (案件立案切片)

Legal.Domain (案件聚合根)

Legal.Contracts (公开契约与事件)


模块物理项目标准结构

每个标准业务领域模块均划分为 3 个物理 .csproj 工程:

工程名称物理命名核心定位与包含内容允许被哪些项目引用
1. 公开契约层*.Contracts模块对外暴露的只读查询模型、集成事件契约(IIntegrationEvent)与请求 DTO允许任何外部业务模块引用
2. 领域内核层*.Domain统一聚合根、实体、值对象、领域事件与仓储接口契约仅限当前模块的 Application 层引用
3. 应用切片层*.Application (或无后缀)垂直切片(Commands / Queries / Rules / Handlers)、IAppModule 装配根仅限 API Host / AppHost 宿主组合根引用

跨模块协作的 5 条硬性约束

为了防止模块边界退化,所有业务模块必须严格遵守以下 5 条铁律:

  1. 单向契约依赖:跨模块项目引用(ProjectReference)只允许指向目标模块的 *.Contracts 包;
  2. 查询走只读端口或读模型:模块 A 如需获取模块 B 的数据,必须通过 B 暴露在 Contracts 中的只读查询端口或共享读模型,严禁直接注入对方的 IAggregateRepository;
  3. 关键状态广播走集成事件:当领域状态发生变更时,通过 CAP 事务性发件箱发布集成事件(IIntegrationEvent),下游模块基于“至少一次(At-Least-Once)”原则幂等消费;
  4. 事务原子性保障:需要与业务持久化保证强一致的消息,必须在聚合根所在的同一个数据库事务中提交至本地 Outbox 表;
  5. 领域事件仅限模块内部:聚合根产出的 DomainEvent 仅在当前请求的事务内同进程流转,不得直接跨模块广播。

IAppModule 编译期模块装配机制

BitzOrcas 废弃了运行时反射扫描装配。每个模块在根目录下实现 IAppModule 契约,供 Host 静态装配:

src/Modules/Legal/BitzOrcas.Modules.Legal/LegalModule.cs
using BitzOrcas.Application.Abstractions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace BitzOrcas.Modules.Legal;
/// <summary>
/// 法律业务模块静态装配根
/// </summary>
/// <remarks>
/// 实现 <see cref="IAppModule"/> 接口,供 Host 在编译期无反射静态注册。
/// </remarks>
public sealed class LegalModule : IAppModule
{
public string Name => "Legal";
public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
// 1. 注册模块特有的领域计算器或适配器
// 2. 垂直切片 Handler 会由 Roslyn 增量生成器自动扫描并生成静态注册代码
}
}

ArchUnit 自动化架构守卫防线

在 tests/BitzOrcas.Architecture.Tests/ModuleBoundaryTests.cs 中,ArchUnit 会在 CI 构建期间强制扫描全仓依赖:

tests/BitzOrcas.Architecture.Tests/ModuleBoundaryTests.cs
using ArchUnitNET.Domain;
using ArchUnitNET.Fluent;
using ArchUnitNET.Loader;
using ArchUnitNET.xUnit;
using Xunit;
using static ArchUnitNET.Fluent.ArchRuleDefinition;
namespace BitzOrcas.Architecture.Tests;
public sealed class ModuleBoundaryTests
{
// 1. 加载所有业务模块程序集元数据
private static readonly Architecture Architecture =
new ArchLoader().LoadAssemblies(
typeof(Legal.LegalModule).Assembly,
typeof(Legal.Domain.MatterIntake).Assembly).Build();
[Fact]
public void ExternalModules_MustNotDependOn_InternalModuleImplementations()
{
// 2. 架构红线:外部模块严禁依赖 Legal 模块内部 Domain 与 Application 实现
IArchRule rule = Types().That()
.ResideInNamespace("BitzOrcas.Modules.Billing..")
.ShouldNot()
.DependOnAny(Types().That().ResideInNamespace("BitzOrcas.Modules.Legal.Domain.."));
rule.Check(Architecture);
}
}

总结

BitzOrcas.Modern 的模块化单体设计确保了:

  • 物理强隔离:团队分工清晰,模块代码自包含;
  • 架构自愈:ArchUnit 自动化测试随时拦截违规依赖;
  • 演进自由:未来若业务需要拆分为独立微服务,只需将物理模块工程剥离部署,无需重构内部领域逻辑。

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%