PlantUML C4 架构图:上下文、容器和组件

··Updated ·8 min read
plantumlc4 模型软件架构c4-plantuml

PlantUML C4 架构图将 PlantUML 渲染能力与 C4 模型的架构词汇结合起来。借助 C4-PlantUML 库,你可以使用 PersonSystemContainerComponentRel 等宏来描述人员、软件系统、容器和组件。

本教程以一个在线商店为例,从系统上下文逐步深入到容器视图和组件视图。如需了解其他图表类型,请从 PlantUML 示例指南开始。

要点总结

  • C4 采用多个缩放层级;上下文、容器和组件视图分别回答不同的问题。
  • C4-PlantUML 是由宏和辅助工具组成的 PlantUML 库,并非独立的渲染器。
  • 使用 !include <C4/C4_Context> 及相关标准库引用,可以简洁地完成设置。
  • 从持续变化的分支进行远程引用虽然方便,却可能导致构建无法复现。
  • 渲染后的 C4 架构图用于传达架构,但不会验证运行时拓扑、安全性或代码一致性。

C4 包含哪些层级?

C4 代表 Context(上下文)、Container(容器)、Component(组件)和 Code(代码)。官方 C4-PlantUML 仓库重点支持前三个层级(检索于 2026 年 7 月 24 日)。

  • 系统上下文展示人员、待分析的系统及外部系统。
  • 容器展示系统内部可部署或可运行的应用与数据存储。
  • 组件展示某个容器内部的重要职责。
  • 代码深入到实现细节,通常由常规 UML 类图或生成的文档来呈现。

不要把所有层级都放在同一画布上。每个视图都应有明确的受众和问题。

前置条件与引用选项

你需要 PlantUML 及 C4-PlantUML 定义。PlantUML 发布的标准库支持如下引用:

!include <C4/C4_Context>

容器或组件视图可使用:

!include <C4/C4_Container>
!include <C4/C4_Component>

组件定义建立在容器宏之上。项目的 PlantUML 标准库文档介绍了标准库机制。

远程 URL 也是 PlantUML 的一种引用机制,但它依赖 OnUML 所配置渲染服务的网络访问能力,可能独立于图表发生失败或变化。在 OnUML 工作流中,应先使用标准库 <C4/...> 引用,并在保存或导出前检查预览。

第 1 步:绘制系统上下文

上下文视图定义系统边界及其关系,但不展示内部应用。

@startuml
!include <C4/C4_Context>

title Online Shop - System Context

Person(customer, "Customer", "Browses products and places orders")
System(shop, "Online Shop", "Sells products through the web")
System_Ext(payment, "Payment Provider", "Authorizes card payments")
System_Ext(email, "Email Service", "Sends order confirmations")

Rel(customer, shop, "Browses and buys", "HTTPS")
Rel(shop, payment, "Requests authorization", "HTTPS/JSON")
Rel(shop, email, "Sends messages", "HTTPS/JSON")

SHOW_LEGEND()
@enduml

使用 System_Ext 表示待分析系统所有权边界之外的系统。在这个视图中,“外部”描述的是架构边界,并不一定意味着不同公司或网络。

第 2 步:深入到容器

在 C4 术语中,容器是应用或数据存储,不一定是 Docker 容器。使用 System_Boundary 将在线商店的内部容器组合起来。

@startuml
!include <C4/C4_Container>

title Online Shop - Container View

Person(customer, "Customer", "Places orders")
System_Ext(payment, "Payment Provider", "Authorizes payments")
System_Ext(email, "Email Service", "Sends confirmations")

System_Boundary(shop, "Online Shop") {
  Container(web, "Web Application", "Next.js", "Serves the customer experience")
  Container(api, "Commerce API", "Java", "Handles catalog and ordering")
  Container(worker, "Order Worker", "Java", "Processes background order tasks")
  ContainerDb(db, "Commerce Database", "PostgreSQL", "Stores customers, products, and orders")
  ContainerQueue(queue, "Order Events", "Message broker", "Carries order events")
}

Rel(customer, web, "Uses", "HTTPS")
Rel(web, api, "Calls", "HTTPS/JSON")
Rel(api, db, "Reads and writes", "SQL")
Rel(api, payment, "Authorizes payments", "HTTPS/JSON")
Rel(api, queue, "Publishes events")
Rel(worker, queue, "Consumes events")
Rel(worker, email, "Sends confirmations", "HTTPS/JSON")

SHOW_LEGEND()
@enduml

技术标签应当有助于决策。如果它们只会让视图过时,而不能帮助受众理解,就应省略或改用更宽泛的描述。

第 3 步:深入到组件

选择一个容器,展示其主要内部职责。下面的视图展开 Commerce API。

@startuml
!include <C4/C4_Component>

title Commerce API - Component View

Container_Boundary(api, "Commerce API") {
  Component(orderController, "Order Controller", "HTTP adapter", "Accepts order requests")
  Component(orderService, "Order Service", "Application service", "Coordinates order placement")
  Component(pricing, "Pricing Component", "Domain component", "Calculates totals")
  Component(orderRepository, "Order Repository", "Persistence adapter", "Stores and loads orders")
  Component(eventPublisher, "Event Publisher", "Messaging adapter", "Publishes order events")
}

ContainerDb_Ext(db, "Commerce Database", "PostgreSQL", "Stores commerce data")
ContainerQueue_Ext(queue, "Order Events", "Message broker", "Carries order events")
System_Ext(payment, "Payment Provider", "Authorizes payments")

Rel(orderController, orderService, "Calls")
Rel(orderService, pricing, "Calculates price with")
Rel(orderService, payment, "Requests authorization", "HTTPS/JSON")
Rel(orderService, orderRepository, "Persists through")
Rel(orderRepository, db, "Reads and writes", "SQL")
Rel(orderService, eventPublisher, "Publishes through")
Rel(eventPublisher, queue, "Sends events to")

SHOW_LEGEND()
@enduml

组件名称应描述职责,而不是照搬每一个源代码目录。如果评审者需要查看 Order Service 内部的成员级细节,请改用 PlantUML 类图

第 4 步:保持关系和布局一致

Rel(from, to, label, technology) 提供一致的关系表达方式。使用简短的动作标签,例如“Calls”“Publishes”或“Reads and writes”;可选的技术参数只用于真正重要的信息。

C4-PlantUML 还提供布局辅助工具和方向性关系宏。仓库的布局选项参考记录了当前选项。应将布局视为提高可读性的辅助,而非架构本身:移动一个框不会改变所有权或依赖关系。

布局变得困难时:

  1. 删除无法回答当前视图问题的元素。
  2. 缩短描述和关系标签。
  3. 将面向不同受众的内容拆分为独立图表。
  4. 先简化内容,再添加方向辅助工具。
  5. 使用发布环境中确切的 PlantUML 和 C4-PlantUML 版本测试输出。

C4 如何与时序图、类图和 ER 图配合

C4 架构图用于建立边界和职责。其他图表可补充有针对性的细节:

  • 使用 PlantUML 时序图指南展示跨越 Web Application、Commerce API 和 Payment Provider 的请求。
  • 使用 PlantUML 类图指南展示 Order Service 内部的类型。
  • 使用 PlantUML ER 图指南展示 Commerce Database 中存储的数据结构。

将这些视图相互链接,比强行把运行时行为、领域类型、存储字段和部署边界塞进同一张图更易于维护。

可复现的引用策略

策略优点权衡
!include <C4/...>使用 OnUML 可用的 PlantUML 标准库内置库可能与最新仓库版本不同
内联定义图表源代码包含所有必需定义源代码更长,也更难更新
远程提交 URL明确指定某个库版本依赖 Web 渲染器访问远程资源
浮动分支 URL快速访问仓库当前内容即使图表没有修改,输出也可能变化

在 OnUML 中,应先使用标准库 <C4/...> 引用并检查渲染预览。视觉稳定性很重要时,请导出一份参考 SVG。

C4-PlantUML 常见错误

问题结果更好的做法
将“Container”理解为“Docker container”重要应用被遗漏使用 C4 定义:应用或数据存储
所有 C4 层级同时出现图表没有明确受众每个缩放层级创建一个视图
使用浮动的远程引用渲染可能意外变化或失败优先使用标准库或固定源
每个标签都以技术为主架构变成技术清单仅包含与决策相关的技术
对方向布局约束过多源代码变得脆弱添加布局提示前先简化元素
假定图表与生产环境一致文档悄然偏离实际定期评审或生成架构证据

常见问题解答

C4-PlantUML 是 PlantUML 的一部分吗?

C4-PlantUML 由 plantuml-stdlib 组织维护,可通过 PlantUML 标准库使用。它提供由 PlantUML 渲染的宏和辅助工具。

应该使用哪个引用?

上下文视图使用 C4_Context,容器视图使用 C4_Container,组件视图使用 C4_Component。请选择支持当前视图的最小文件。

应该使用远程引用吗?

远程引用依赖 Web 渲染器的访问能力,可能在图表本身没有问题时失败。在 OnUML 中,如果标准库 <C4/...> 引用包含所需宏,应优先使用它,并在保存或导出前检查预览。

可以在哪里比较 Mermaid 和 C4-PlantUML?

如果目的是选择工具,而不是学习 C4-PlantUML,请参阅现有的 Mermaid 与 PlantUML C4 架构图对比

后续步骤

先创建上下文视图,与技术和非技术利益相关者共同检查系统边界。然后只为你所拥有的系统添加容器视图,并针对需要讨论内部设计决策的容器创建组件视图。

回到 PlantUML 示例中心,使用时序图教程衔接行为,并将 C4-PlantUML 仓库及其示例目录作为权威宏参考。