de_DEen_USes_ESfa_IRfr_FRhi_INid_IDjapl_PLpt_PTru_RUvizh_CNzh_TW

C4 模型第3层深入:掌握组件图以揭示内部结构与职责

什么是 C4 组件图?

组件图是第3层西蒙·布朗的 C4 模型中。它聚焦于一个特定的容器(来自第2层容器图)以展示:

The Ultimate Guide to C4 Model Visualization with Visual Paradigm's AI  Tools - ArchiMetric

  • 该容器的逻辑构建块(组件)构成该容器的各个部分。

  • 这些组件之间如何交互彼此交互。

  • 职责以及实现技术(高于类的层次——例如 Spring Bean、模块、服务、控制器、外观等)。

  • 关键接口契约组件之间的(通常通过关系隐含)。

重要说明:C4 中的“组件”并非并非一个类。它是一个类的逻辑分组位于明确定义的接口之后——具有明确职责,可以在容器内相对独立地进行开发/测试/部署,但并非像容器那样可独立部署。

组件示例:

  • REST 控制器 / Web 控制器

  • 服务 / 用例 / 应用服务

  • 仓库 / 数据访问对象

  • 领域模型 / 实体

  • 安全 / 认证模块

  • 通知发送器

  • 对外部系统的外观

  • 业务规则引擎

  • 缓存层

该图保持逻辑上 / 实现无关性足够—— 不包含类属性、方法签名或完整的 UML 类细节(那是第 4 级代码,可选且罕见)。

何时创建组件图

创建(并维护)组件图仅当:

  • 所选容器是足够复杂仅凭其名称和描述无法明显看出其内部结构。

  • 新团队成员(尤其是后端开发人员)经常问:“这个服务/API 内部是如何实际实现功能 X 的?”

  • 你正在重构拆分,或提取容器内部的逻辑,需要明确边界/职责。

  • 你正在进行详细的设计讨论代码审查,或值班交接用于特定容器。

  • 您希望记录关键的架构决策在容器内部(例如,六边形架构、垂直切片、CQRS分离、安全执行点)。

  • 您已识别出技术债务上帝类,或紧耦合在容器内部,希望在清理前可视化当前状况。

  • 您正在引入资深开发人员/架构师,他们需要快速理解模块结构。

不要为以下情况创建组件图:

  • 简单的容器(带一个控制器 + 一个服务 + 一个仓库的 CRUD API — 结构明显)。

  • 大多数微服务(通常足够小,容器级别已足够)。

  • 前端容器(React/Vue 应用 — 通常用组件树或 Storybook 展示更佳)。

  • 当第2层(容器)加上良好的代码结构/命名已能传达所有必要信息时。

Simon Brown 建议:大多数团队在第1层 + 第2层即可停止。只有在以下情况才需要进入第3层:复杂 / 高风险 / 核心 / 高变动容器。

为何使用组件图?(主要优势)

  • 明确内部职责—— 展示关注点分离(例如,控制器 vs 服务 vs 数据访问 vs 外部集成)。

  • 揭示耦合与依赖关系 — 可以清晰展示上帝组件、循环依赖或对基础设施代码的过度依赖。

  • 支持更高效的入职培训与交接工作 — 开发人员比阅读所有源代码文件能更快地理解模块边界。

  • 指导重构与演进 — 在拆分单体架构或引入模式(端口与适配器、垂直切片)前后,提供可视化基线。

  • 支持架构评审与威胁建模 — 明确指出验证、授权、日志记录等操作发生的位置。

  • 架构即代码 — 当存储在 PlantUML 中时,可与代码库一同版本化,支持差异对比,并可在 PR 中审查。

  • 提升沟通效率 — 资深开发者关注组件职责;初级开发者更关心新代码应放在何处。

如何创建出色的组件图(分步指南 + 最佳实践)

  1. 选择一个容器 — 从最复杂或业务关键的容器开始(通常是主 API / 后端服务)。

  2. 从第2层复制上下文 — 包含与该容器交互的外部参与者(其他容器、人员、外部系统)。

  3. 绘制容器边界 — 使用 Container_Boundary 在 PlantUML 中使用,以清晰界定“此容器内部”的范围。

  4. 识别组件 — 询问:

    • 内部的主要模块 / Spring Bean / 包 / 限界上下文有哪些?

    • 传入请求落在何处?(控制器/处理器)

    • 业务逻辑在何处被协调?

    • 数据在何处被访问 / 缓存 / 验证?

    • 横切关注点在何处处理?(安全、日志)

    • 是否存在到遗留系统/外部系统的外观层或防腐层?

  5. 添加技术与简要说明 — 名称、技术(Spring 服务、.NET 处理器、Go 模块等),简短用途(少于15个字)。

  6. 定义交互 — 显示方向和意图(使用、调用、读取、发布事件到)。在此层级协议通常省略。

  7. 最佳实践

    • 限制范围 — 每张图最多6–12个组件。如果更多 → 创建聚焦的子视图(例如“认证切片”)。

    • 有意义地命名 — 优先使用“订单提交服务”而非“OrderService”。

    • 展示职责,而非类 — 避免列出每个类;进行逻辑分组。

    • 谨慎使用图标 — 仅在有助于说明技术时使用(如Spring、.NET图标)。

    • 启用图例 — 帮助新读者理解。

    • 保持布局整洁 — LAYOUT_WITH_LEGEND()LAYOUT_TOP_DOWN().

    • 版本存于代码仓库 — .puml文件与容器代码存放在一起。

    • 迭代 — 在重构冲刺或每季度架构健康检查期间更新。

PlantUML 示例 – 互联网银行系统 API 应用程序(经典大银行 plc 风格)

以下是一个使用官方 C4-PlantUML 库的生产级别示例——这是最常被引用的实际案例。

@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml

title 组件图:互联网银行系统 - API 应用程序

' 演员 / 容器层级的外部部分
Container(spa, "单页应用", "JavaScript & Angular", "通过浏览器提供互联网银行用户界面")
Container(mobile, "移动应用", "iOS/Android", "提供有限的移动银行功能")
ContainerDb(database, "银行数据库", "PostgreSQL", "存储用户偏好、缓存数据、会话")
System_Ext(mainframe, "核心银行系统", "大型机 – 核心账户与交易")

' 我们正在深入的容器
Container_Boundary(api, "API 应用程序") {
    Component(signInCtrl, "登录控制器", "Spring MVC REST 控制器", "处理认证与会话创建")
    Component(accountsCtrl, "账户概览控制器", "Spring MVC REST 控制器", "提供账户余额与概览")
    Component(resetPwdCtrl, "重置密码控制器", "Spring MVC REST 控制器", "管理密码重置流程")
    
    Component(security, "安全组件", "Spring Bean", "JWT令牌、密码哈希、角色检查")
    Component(accountService, "账户管理组件", "Spring Bean / 服务", "协调账户查询与业务规则")
    Component(mainframeFacade, "大型机银行门面", "Spring Bean", "与遗留大型机之间的反腐败层")
    Component(emailNotifier, "邮件通知组件", "Spring Bean", "发送确认与重置邮件")
}

' 边界内的关系
Rel(signInCtrl, security, "使用")
Rel(accountsCtrl, accountService, "使用")
Rel(resetPwdCtrl, security, "使用")
Rel(resetPwdCtrl, emailNotifier, "使用")
Rel(accountService, mainframeFacade, "使用")
Rel(accountService, database, "读取并写入", "JDBC")
Rel(mainframeFacade, mainframe, "使用", "XML/HTTPS")
Rel(emailNotifier, database, "读取用户偏好", "JDBC")

' 来自前端的调用
Rel(spa, signInCtrl, "使用", "JSON/HTTPS")
Rel(spa, accountsCtrl, "使用", "JSON/HTTPS")
Rel(spa, resetPwdCtrl, "使用", "JSON/HTTPS")
Rel(mobile, signInCtrl, "使用", "JSON/HTTPS")
Rel(mobile, accountsCtrl, "使用", "JSON/HTTPS")
Rel(mobile, resetPwdCtrl, "使用", "JSON/HTTPS")

LAYOUT_WITH_LEGEND()
LAYOUT_LEFT_RIGHT()

@enduml

这将生成:

  • API容器周围有清晰的边界

  • 控制器、服务、门面的逻辑分组

  • 明确的职责

  • 关键交互与依赖

  • 自动图例以提高可读性

粘贴到 PlantUML 渲染器(在线或 IDE)中——根据您的系统自定义名称/技术

将此模式作为您的起始模板。目标始终是有效的团队沟通——而非图表美观。愉快建模!

C4 组件图资源