ARTICLE · 1047049
第13讲:软件系统建模:部署图
发布时间:2026-09-20 23:14:10 最近访问:2026-09-20 23:14:10
第13讲:软件系统建模:部署图
软件系统并不是只存在于源代码和设计文档中。一个软件系统最终需要运行在具体的计算机、服务器、移动设备、虚拟机、容器或云平台上,并通过网络与其他系统和基础设施进行通信。部署图(Deployment Diagram)用于描述软件系统的运行环境以及软件制品在这些环境中的部署关系。它把软件系统从“逻辑结构”映射到“运行环境”,因此是连接软件设计与实际运行环境的重要建模工具。在软件工程过程中,部署图并不只在系统设计完成之后才有价值。在需求分析阶段,部署图可以帮助开发人员和用户明确系统需要依赖哪些类型的设备、运行环境以及外部系统;进入系统设计阶段后,则可以进一步描述服务器、虚拟机、容器、数据库、网络节点以及软件制品之间的具体部署关系。部署图是 UML(Unified Modeling Language,统一建模语言)中的一种结构图,用于描述系统在运行环境中的物理部署结构。简单来说,部署图回答以下几个问题:这个图表达的核心信息不是“程序有哪些类”,而是:Web 服务、应用程序、数据库和缓存分别运行在哪里,以及它们之间如何连接。软件系统必须运行在某种计算资源之上,例如:PC;手机;服务器;虚拟机;Docker 容器;Kubernetes Pod;云服务器;数据库服务器;网络设备等。这里表达的是:order-service 被部署在Application Server 上。图中不仅可以表示节点之间存在连接,还可以进一步标明通信协议或通信方式。设计阶段的部署图可以帮助开发团队讨论:需要多少台服务器;哪些服务应该独立部署;哪些服务共享服务器;数据库部署在哪里;是否需要负载均衡;是否需要缓存;是否需要消息队列;哪些节点位于内网;哪些节点可以被互联网访问。因此,部署图不仅是一种 UML 文档,也可以成为软件架构和基础设施设计的重要辅助工具。部署图的核心语法可以概括为:节点+ 软件制品 + 关系。下面分别介绍。节点表示一个可以承载软件运行的计算资源或运行环境。在 UML 中,节点通常用一个立方体或带有节点标识的矩形表示。常见节点包括:用户计算机、手机、Web 服务器、应用服务器、数据库服务器、虚拟机、容器、云主机。执行环境节点表示运行软件的环境,例如 JVM、Docker Container、Application Server 等。这表达了:物理服务器上运行JVM,JVM 中运行应用程序。制品(Artifact)表示系统中实际被部署和运行的物理软件产物。例如:shop.war、shop.jar、app.exe、Docker Image、Web 前端静态文件、配置文件;数据库脚本等。可以表示为带有《artifact》的矩形框:组件(Component)和制品(Artifact)不是同一个概念。组件更多描述软件的逻辑模块,例如:Order Service、Payment Service、User Service,而制品强调实际被部署的物理软件产物,例如:order-service.jar、payment-service.jar、user-service.jar。部署关系表示某个软件制品被部署到某个节点或运行环境中。它表示一个或多个软件制品(Artifact)、组件或子系统被放置并运行在节点(Node)上。它是一种特殊的依赖关系(Dependency),带有 <<deploy>> 关键字。明确指出软件资产(如.jar、.exe、配置文件、数据库文件)物理上存放在哪台硬件设备或执行环境中。表现形式:带箭头的虚线,箭头指向节点。例如:在 UML 中,可以通过部署关系表示这种关系。如果采用文字化表示,表示shop.jar 运行在 Application Server 上。通信关系表示两个节点(Node)之间的物理连接或网络通信链路(如网线、Wi-Fi、光纤等)。它本质上是 UML 中关联关系(Association)的一种特殊化(带有 <<communication >> 关键字,但在日常绘图中通常直接用连线表示)。它用于展示服务器与服务器、客户端与服务器之间的网络拓扑和通信协议,比如,HTTP、HTTPS、TCP、JDBC、REST、gRPC、WebSocket、AMQP,其他系统约定的通信协议。例如:需要注意,通信路径表示的是运行节点之间的通信关系,并不意味着一定要把每一个网络设备都画出来。2.5 包含/嵌套关系 (Containment / Nesting)包含/嵌套关系表示一个物理实体(节点、制品或执行环境)在物理上被包含在另一个节点内部。它表达层次化结构,例如,一台物理服务器内部包含多个虚拟机,或者虚拟机内部运行着特定的容器和软件。直接将子元素画在父节点的图形框内部(不需要画箭头)。实际绘图时并不要求所有层次都必须出现。部署图应该根据当前阶段和建模目的决定详细程度。Manifest 关系是一种特殊的抽象关系(Abstraction)。它用来表示软件制品(Artifact,如 .jar、.exe、源文件)与它所实现的逻辑模型元素(如组件 Component、类 Class)之间的对应关系。在逻辑上的“组件(Component)”是一个抽象的设计概念(比如“订单服务组件”),而物理上的“制品(Artifact)”是它落地后的具体产物(比如 order-service.jar 文件)。<<manifest>> 就是用来连接这两者的纽带,意思是“这个物理文件具体实现了那个逻辑组件”。它的图形表示用带有一根虚线和一个空心箭头,并在线上标注<<manifest>>,并且由制品(Artifact)指向逻辑元素(Component / Class)。依赖关系 (Dependency)表示一个元素在运行或编译时需要另一个元素的支持。如果被依赖的元素发生变化,依赖方可能会受到影响。在部署图中,常用于表示制品之间、配置与应用之间的依赖。依赖关系用带箭头的虚线,由依赖方指向被依赖方。泛化关系 (Generalization / 继承)表示节点或制品之间的“一般与特殊”关系(即面向对象中的继承概念)。较少使用,但当系统中存在多种同类硬件(例如“标准服务器”和“高配服务器”都继承自抽象的“服务器节点”)时可以使用。泛化关系用带空心三角形的实线,由子节点指向父节点。关系名称 | 关键字 / 符号 | 连接对象 | 核心含义与作用 | 典型应用场景 |
通信关系 (Communication ) | <<communication >> (通常为实线连线) | 节点↔ 节点 (Node ↔ Node) | 描述硬件节点之间的物理连接或网络通信链路。 | Web 服务器与数据库服务器之间的 TCP/IP 网络连接。 |
部署关系 (Deployment) | <<deploy>> (带箭头的虚线) | 制品→ 节点 (Artifact → Node) | 表示软件制品(文件、程序)被放置并运行在哪个硬件设备或执行环境中。 | 将app.jar部署到 Tomcat 容器中。 |
表现关系 (Manifest) | <<manifest>> (带箭头的虚线) | 制品→ 逻辑元素 (Artifact → omponent/Class) | 桥接”逻辑与物理”。表示某个物理文件具体实现了哪个高层逻辑组件。 | order-service.jar文件实现了“订单管理模块”这一逻辑组件。 |
嵌套关系 (Containment) | 空间包含 (无特定关键字) | 节点⊂ 父节点 或制品⊂ 节点 | 表示物理或逻辑上的包含、包裹关系,常用于表达多层架构。 | 物理服务器内部包含虚拟机,虚拟机内部包含 Docker 容器。 |
依赖关系 (Dependency) | 虚线箭头 (可配自定义关键字) | 任意元素→ 任意元素 | 表示一个元素在运行或编译时需要另一个元素的支持。 | 应用程序的配置文件依赖于特定的环境变量。 |
泛化关系 (Generalization) | 实线空心三角箭头 | 子元素→ 父元素 | 面向对象中的继承概念,表示同类硬件或软件的“一般与特殊”归纳。 | “高配服务器”和“标准服务器”继承自抽象的“服务器节点”。 |
这是软件工程实践中非常容易混淆的一个问题。很多初学者认为:部署图只有系统设计完成之后才能画。实际上,在需求分析阶段就可以使用部署图。但是,需求阶段的部署图与设计阶段的部署图关注点不同。需求阶段的部署图主要描述:系统需要运行在什么类型的环境中,以及系统与哪些外部设备或系统发生交互。它关注的是环境需求,而不是具体的技术实现。此时我们可能还不知道:使用什么数据库,用什么 Web 框架、使用 Docker 还是虚拟机、使用 Java 还是 C#、使用什么云平台。但我们已经可以明确、系统存在管理员终端、系统存在服务器、系统需要与门禁设备通信、系统需要与学校认证系统通信。这些都是需求层面的信息。需求阶段应该避免过早确定技术。如果需求规格说明中并没有这些技术约束,那么这种图很可能已经进入了设计层面。需求阶段更适合描述:用户终端-->应用服务器-->数据存储系统。而不是过早指定技术:React、Spring Boot、Kubernetes、PostgreSQL、Redis、Kafka。进入系统设计阶段以后,部署图需要进一步回答:系统具体如何部署和运行?因此,设计阶段的部署图通常更加具体。例如:这里已经涉及:负载均衡、多台应用服务器、Redis、MySQL、网络通信、用制品。这些都是设计阶段的重要内容。对比维度 | 需求阶段 | 设计阶段 |
核心问题 | 系统需要什么运行环境? | 系统具体如何部署? |
主要关注 | 环境需求、设备、外部系统 | 服务器、容器、软件制品、网络 |
技术细节 | 较少 | 较多 |
服务器数量 | 通常不确定 | 可以明确 |
数据库类型 | 通常不确定 | 可以明确 |
中间件 | 通常不指定 | 可以指定 |
云平台 | 通常不指定 | 可以指定 |
Docker/Kubernetes | 通常不涉及 | 可以涉及 |
主要用途 | 明确环境需求和系统边界 | 指导系统实现、部署和运维 |
可以把它们概括成一句话:需求阶段关注“系统需要在哪里运行”,设计阶段关注“系统究竟怎样运行”。因此,部署图并不是“一次画完”的。它可以随着软件开发过程逐渐细化。首先明确要描述哪个系统。例如:本部署图描述网上商城系统的运行环境。不要一开始就急着画服务器。考虑用户和系统通过什么设备访问系统:PC;手机;平板;IoT 设备;门禁设备;POS 终端等。确定软件需要运行在哪些节点上:Web Server、Application Server、Database Server、Message Queue Server、Cache Server。需求阶段可以使用较抽象的名称。设计阶段则可以进一步具体化。明确哪些软件制品需要被部署:frontend.zip、shop.war、order-service.jar、payment-service.jar。部署图看起来简单,但在实际建模中很容易出现一些问题。这可能是网络拓扑图,但不一定是有效的软件部署图。部署图应该重点回答:软件部署在哪里?运行环境之间是什么关系?如果只是画交换机、路由器、网线,却没有软件部署信息,那么它更接近网络拓扑图。这通常不是一个好的部署图。User、Order、Product 等如果表示程序中的类,那么它们属于类模型,而不是部署模型。例如:Order Service、Payment Service、User Service,这些描述的是软件的逻辑组成,更接近组件图。部署图应该进一步回答:例如在需求阶段直接指定:Kubernetes、Docker、Spring Boot、Redis、MySQL、AWS。如果这些技术尚未成为需求约束,那么这种表达容易把需求和设计混在一起。需求阶段应该尽量保持技术中立。这样的图对于详细设计而言可能信息不足。如果已经确定:有两台应用服务器、使用负载均衡、使用 Redis、使用消息队列、数据库独立部署,那么这些关键部署信息应该体现在设计阶段的部署模型中。部署图不是“系统所有信息的集合”。例如把以下内容全部画进去:所有类;所有接口;所有数据库表;所有 IP;所有端口;所有交换机;所有防火墙;所有服务器;所有 API。最终会得到一张难以阅读的图。更好的做法是:一张图表达一个层次、一个视角或一个主要问题。可以分别建立:系统级部署图;应用级部署图;生产环境部署图;测试环境部署图;云平台部署图。绘制部署图时,一个重要原则是:图的详细程度应该与当前开发阶段和建模目的相匹配。可以采用以下三个层次。软件架构图通常强调:系统在逻辑上由什么组成,以及这些部分如何协作。部署图强调:这些软件最终运行在哪里,以及运行环境之间如何连接。此时重点是确定:学生需要访问系统、教师需要访问系统、系统需要数据存储、系统需要视频服务。此时部署图已经可以支持:服务器部署、容量规划、网络设计、高可用设计、软件部署、运维讨论。部署图用于描述软件系统的运行时部署结构。它重点表达软件、运行环境、计算节点以及通信关系之间的联系。学习部署图时,可以抓住四个核心概念:节点、运行环境、软件制品、通信关系。在软件开发生命周期中,部署图可以随着系统逐渐细化:因此,需求阶段和设计阶段的部署图并不是两种完全不同的 UML 图,而是针对不同开发阶段、具有不同抽象程度和建模目的的部署模型。设计阶段主要回答:“系统具体如何部署到这些运行环境中?”一个好的部署图既不能过于抽象,使其失去实际意义;也不能包含大量与当前建模目的无关的技术细节。建模人员应根据软件开发阶段、读者对象以及建模目的选择适当的抽象层次。