本文档是《ASP.NET Core → Spring迁移对照系列》的编译生态篇分篇。
版本基线
| 类别 | 版本 |
|---|---|
| C# | 12(.NET 8) |
| Java | 17(LTS) |
| Spring Boot | 3.2.x |
| ASP.NET Core | 8.0 |
| NuGet | 6.x |
| Maven | 3.9.x |
十八、包管理对照
| .NET (NuGet) | Java (Maven) | 用途 |
|---|---|---|
dotnet add package X |
<dependency> 标签 |
添加依赖 |
dotnet remove package X |
删除 dependency 标签 | 移除依赖 |
dotnet list package |
mvn dependency:tree |
查看依赖树 |
dotnet add package X --version 1.0 |
<version> 标签 |
指定版本 |
NuGet.config |
pom.xml + settings.xml |
仓库配置 |
18.1 中央仓库配置
- ASP.NET Core :NuGet.org 官方仓库默认即用;私有仓库通过
NuGet.config配<packageSources>节点指向公司 Nexus / Artifactory。 - Java :Maven Central 默认即用;私有仓库通过
~/.m2/settings.xml的<mirrors>节点把请求代理到公司 Nexus(按*通配符拦截所有中央仓库请求)。
settings.xml 核心片段:
xml
<mirrors>
<mirror>
<id>company-nexus</id>
<name>Company Nexus</name>
<url>http://nexus.internal/repository/maven-public/</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
18.2 Maven 私服管理 3 万设备协议 SDK
公司搭建 Nexus 私服,集中托管 3 万设备协议相关的私有 jar:
- 设备协议适配库:
com.iot:device-protocol-mqtt:1.2.0(EMQX 桥接) - 设备协议适配库:
com.iot:device-protocol-modbus:1.0.5(工业网关) - 设备协议适配库:
com.iot:device-protocol-coap:1.1.0(NB-IoT 场景) - 内部通用组件:
com.iot:iot-common:2.4.0(Result / TraceId / PageRequest)
通过 settings.xml 的 mirror 拦截所有中央仓库请求,统一走公司私服,下载速度从公网 200 KB/s 提升到内网 50 MB/s,全量 clean install 从 18 分钟压缩到 90 秒。
18.3 停车场场景:多模块 Maven 项目
停车场系统拆 5 个 Maven 模块:
parking-parent(pom 父,统一版本与依赖管理)parking-common(公共工具:Result / 异常 / 常量)parking-auth(鉴权:JWT / 车牌黑名单)parking-gate(出入口:车牌识别 / 抬杆 / 流水)parking-order(订单:创建 / 支付 / 退款)
父 POM 用 <dependencyManagement> 统一定义版本号,子模块 <dependencies> 只引 groupId + artifactId,不指定 version------升级版本只需改父 POM 一处,避免散落在 5 个模块里的版本号漂移。
xml
<!-- parking-parent/pom.xml -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.parking</groupId>
<artifactId>parking-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.3.0</version>
</dependency>
</dependencies>
</dependencyManagement>
另外一种管理方式建立私有的
git仓库服务器,则采用git submodule方式,这种方式其实比较灵活,而且可以配置CI/CD和代码静态扫描工具,最新的方式是采用AI来实现代码走读。
18.4 FAQ
-
Q1:Maven 依赖冲突如何解决?
mvn dependency:tree -Dverbose打印依赖树,定位冲突的 groupId + artifactId,再用<exclusions>排除传递依赖;或就近在 POM 里直接<version>强制锁定。 -
Q2:SNAPSHOT 版本与 RELEASE 版本区别?
RELEASE 一次发布、不可变、长期保存;SNAPSHOT 每次构建都拉最新(带时间戳),用于内部联调。生产环境严禁用 SNAPSHOT------可能出现今天能跑、明天构建失败的诡异问题。
-
Q3:Maven vs Gradle 选型?
Maven 约定大于配置、XML 直观、生态成熟(99% 团队会用);Gradle 基于 Groovy/Kotlin DSL、增量构建更快(大型项目省 30% 时间)、Android 官方默认。
十九、项目结构对照
19.1 数据结构
#mermaid-svg-gWrntW6mYuvFodTa{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gWrntW6mYuvFodTa .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gWrntW6mYuvFodTa .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gWrntW6mYuvFodTa .error-icon{fill:#552222;}#mermaid-svg-gWrntW6mYuvFodTa .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gWrntW6mYuvFodTa .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gWrntW6mYuvFodTa .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gWrntW6mYuvFodTa .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gWrntW6mYuvFodTa .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gWrntW6mYuvFodTa .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gWrntW6mYuvFodTa .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gWrntW6mYuvFodTa .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gWrntW6mYuvFodTa .marker.cross{stroke:#333333;}#mermaid-svg-gWrntW6mYuvFodTa svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gWrntW6mYuvFodTa p{margin:0;}#mermaid-svg-gWrntW6mYuvFodTa .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-gWrntW6mYuvFodTa .cluster-label text{fill:#333;}#mermaid-svg-gWrntW6mYuvFodTa .cluster-label span{color:#333;}#mermaid-svg-gWrntW6mYuvFodTa .cluster-label span p{background-color:transparent;}#mermaid-svg-gWrntW6mYuvFodTa .label text,#mermaid-svg-gWrntW6mYuvFodTa span{fill:#333;color:#333;}#mermaid-svg-gWrntW6mYuvFodTa .node rect,#mermaid-svg-gWrntW6mYuvFodTa .node circle,#mermaid-svg-gWrntW6mYuvFodTa .node ellipse,#mermaid-svg-gWrntW6mYuvFodTa .node polygon,#mermaid-svg-gWrntW6mYuvFodTa .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gWrntW6mYuvFodTa .rough-node .label text,#mermaid-svg-gWrntW6mYuvFodTa .node .label text,#mermaid-svg-gWrntW6mYuvFodTa .image-shape .label,#mermaid-svg-gWrntW6mYuvFodTa .icon-shape .label{text-anchor:middle;}#mermaid-svg-gWrntW6mYuvFodTa .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gWrntW6mYuvFodTa .rough-node .label,#mermaid-svg-gWrntW6mYuvFodTa .node .label,#mermaid-svg-gWrntW6mYuvFodTa .image-shape .label,#mermaid-svg-gWrntW6mYuvFodTa .icon-shape .label{text-align:center;}#mermaid-svg-gWrntW6mYuvFodTa .node.clickable{cursor:pointer;}#mermaid-svg-gWrntW6mYuvFodTa .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gWrntW6mYuvFodTa .arrowheadPath{fill:#333333;}#mermaid-svg-gWrntW6mYuvFodTa .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gWrntW6mYuvFodTa .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gWrntW6mYuvFodTa .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gWrntW6mYuvFodTa .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gWrntW6mYuvFodTa .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gWrntW6mYuvFodTa .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gWrntW6mYuvFodTa .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gWrntW6mYuvFodTa .cluster text{fill:#333;}#mermaid-svg-gWrntW6mYuvFodTa .cluster span{color:#333;}#mermaid-svg-gWrntW6mYuvFodTa div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-gWrntW6mYuvFodTa .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gWrntW6mYuvFodTa rect.text{fill:none;stroke-width:0;}#mermaid-svg-gWrntW6mYuvFodTa .icon-shape,#mermaid-svg-gWrntW6mYuvFodTa .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gWrntW6mYuvFodTa .icon-shape p,#mermaid-svg-gWrntW6mYuvFodTa .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gWrntW6mYuvFodTa .icon-shape .label rect,#mermaid-svg-gWrntW6mYuvFodTa .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gWrntW6mYuvFodTa .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gWrntW6mYuvFodTa .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gWrntW6mYuvFodTa :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 项目结构
.NET: .csproj
Java: pom.xml
src/
Program.cs
Controllers/
Services/
Models/
src/main/java
IotAuthApplication.java
controller/
service/
domain/
19.2 ASP.NET Core 标准结构
MyProject/
├── MyProject.csproj # 项目文件(依赖)
├── Program.cs # 入口(6.0 之前是 Startup.cs)
├── appsettings.json # 配置
├── Controllers/ # 控制器
│ └── UserController.cs
├── Services/ # 业务逻辑
│ └── UserService.cs
├── Models/ # 数据模型
│ └── User.cs
├── Data/ # 数据访问
│ └── AppDbContext.cs
└── Properties/
└── launchSettings.json
19.3 Spring Boot 标准结构
19.3.1 pom.xml 关键配置
xml
<properties>
<java.version>17</java.version>
<spring-boot.version>3.2.5</spring-boot.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
19.3.2 Spring Boot 目录结构
MyProject/
├── pom.xml # Maven 配置(依赖)
├── src/main/java/
│ └── com/example/
│ ├── MyApplication.java
│ ├── controller/ # 控制器
│ │ └── UserController.java
│ ├── service/ # 业务逻辑
│ │ └── UserService.java
│ ├── domain/ # 领域模型
│ │ └── User.java
│ └── repository/ # 数据访问
│ └── UserRepository.java
├── src/main/resources/
│ └── application.yml # 配置
└── src/test/java/
19.4 IoT 平台场景:4 个 IoT 微服务的项目结构
3 万设备 + 4 个 IoT 微服务(设备管理 / 设备监控 / OTA / 协议适配),按业务边界拆分:
iot-platform/
├── iot-common/ # 公共模块(Result / TraceId / PageRequest / 异常)
├── iot-auth/ # 设备鉴权服务(设备注册 / token 校验 / 证书管理)
├── iot-monitor/ # 设备监控服务(心跳 / 状态 / 告警 / 在线统计)
├── iot-ota/ # OTA 升级服务(分批推送 / 进度跟踪 / 回滚)
├── iot-protocol/ # 协议适配(MQTT / CoAP / Modbus / 私有 TCP)
└── iot-gateway/ # 边缘网关聚合(多协议转换 / 设备影子)
拆分依据:
- iot-monitor:QPS 最高(峰值 500 / 秒),独立部署、独立扩缩容
- iot-ota:CPU 密集(差分包生成 + 签名校验),独立部署避免影响实时链路
- iot-protocol:长连接密集(3 万 TCP 连接),专属节点避免挤占业务线程
- iot-auth:调用频次极高(每条消息鉴权),独立 Redis 集群缓存 token
19.5 出入口服务场景:4 大业务模块的项目结构
出入口系统按业务边界拆 5 个模块:
parking-platform/
├── parking-common/ # 公共(鉴权 / 异常 / 统一返回 / TraceId)
├── parking-gate/ # 出入口(车牌识别 / 抬杆 / 流水 / 实时车位)
├── parking-order/ # 订单(创建 / 支付 / 退款 / 发票)
├── parking-billing/ # 计费(按时 / 按次 / 月卡 / 优惠券)
└── parking-admin/ # 后台管理(运营 / 报表 / 设备监控)
模块依赖方向:
parking-admin ──┐
├──> parking-common
parking-gate ──┤
parking-order ─┤
parking-billing ┘
严格单向依赖 ,禁止反向引用(parking-common 不能依赖任何业务模块),保证公共模块零业务污染、可独立升级。
19.6 FAQ
- Q1:Maven 多模块项目如何管理版本?
父 POM 用<dependencyManagement>统一定义版本号,子模块<dependencies>只引groupId + artifactId不指定 version;父 POM 自身<version>用${revision}变量(CI 构建时统一替换)。 - Q2:Spring Boot starter 原理?
本质是 Maven 依赖 + 自动配置(META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports)的组合包;引入 starter 后 Spring Boot 按 classpath 里的类自动装配 Bean,省掉 XML/Configuration 配置。 - Q3:IoT 微服务拆分的依据?
三个维度:业务边界 (鉴权 vs 监控 vs OTA 业务清晰独立)、性能特征 (长连接 vs CPU 密集 vs 高 QPS 资源诉求不同)、变更频率(OTA 升级逻辑经常迭代,需要独立发布不影响实时链路)。
二十、部署对照
Spring Boot 默认 Tomcat,不是 Jetty 或 Netty 。使用
spring-boot-starter-web时,应用运行在 Servlet 栈,默认内嵌 Tomcat;只有使用spring-boot-starter-webflux时,才默认使用 Reactive 栈的 Reactor Netty。Jetty / Undertow 属于可选替代,切换方式见第三十三章。
20.1 数据结构
#mermaid-svg-6utkKi8N0YfmnN17{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-6utkKi8N0YfmnN17 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-6utkKi8N0YfmnN17 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-6utkKi8N0YfmnN17 .error-icon{fill:#552222;}#mermaid-svg-6utkKi8N0YfmnN17 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6utkKi8N0YfmnN17 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-6utkKi8N0YfmnN17 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6utkKi8N0YfmnN17 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6utkKi8N0YfmnN17 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-6utkKi8N0YfmnN17 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6utkKi8N0YfmnN17 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6utkKi8N0YfmnN17 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6utkKi8N0YfmnN17 .marker.cross{stroke:#333333;}#mermaid-svg-6utkKi8N0YfmnN17 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6utkKi8N0YfmnN17 p{margin:0;}#mermaid-svg-6utkKi8N0YfmnN17 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-6utkKi8N0YfmnN17 .cluster-label text{fill:#333;}#mermaid-svg-6utkKi8N0YfmnN17 .cluster-label span{color:#333;}#mermaid-svg-6utkKi8N0YfmnN17 .cluster-label span p{background-color:transparent;}#mermaid-svg-6utkKi8N0YfmnN17 .label text,#mermaid-svg-6utkKi8N0YfmnN17 span{fill:#333;color:#333;}#mermaid-svg-6utkKi8N0YfmnN17 .node rect,#mermaid-svg-6utkKi8N0YfmnN17 .node circle,#mermaid-svg-6utkKi8N0YfmnN17 .node ellipse,#mermaid-svg-6utkKi8N0YfmnN17 .node polygon,#mermaid-svg-6utkKi8N0YfmnN17 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6utkKi8N0YfmnN17 .rough-node .label text,#mermaid-svg-6utkKi8N0YfmnN17 .node .label text,#mermaid-svg-6utkKi8N0YfmnN17 .image-shape .label,#mermaid-svg-6utkKi8N0YfmnN17 .icon-shape .label{text-anchor:middle;}#mermaid-svg-6utkKi8N0YfmnN17 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-6utkKi8N0YfmnN17 .rough-node .label,#mermaid-svg-6utkKi8N0YfmnN17 .node .label,#mermaid-svg-6utkKi8N0YfmnN17 .image-shape .label,#mermaid-svg-6utkKi8N0YfmnN17 .icon-shape .label{text-align:center;}#mermaid-svg-6utkKi8N0YfmnN17 .node.clickable{cursor:pointer;}#mermaid-svg-6utkKi8N0YfmnN17 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-6utkKi8N0YfmnN17 .arrowheadPath{fill:#333333;}#mermaid-svg-6utkKi8N0YfmnN17 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6utkKi8N0YfmnN17 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6utkKi8N0YfmnN17 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6utkKi8N0YfmnN17 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-6utkKi8N0YfmnN17 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6utkKi8N0YfmnN17 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-6utkKi8N0YfmnN17 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6utkKi8N0YfmnN17 .cluster text{fill:#333;}#mermaid-svg-6utkKi8N0YfmnN17 .cluster span{color:#333;}#mermaid-svg-6utkKi8N0YfmnN17 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6utkKi8N0YfmnN17 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-6utkKi8N0YfmnN17 rect.text{fill:none;stroke-width:0;}#mermaid-svg-6utkKi8N0YfmnN17 .icon-shape,#mermaid-svg-6utkKi8N0YfmnN17 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6utkKi8N0YfmnN17 .icon-shape p,#mermaid-svg-6utkKi8N0YfmnN17 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-6utkKi8N0YfmnN17 .icon-shape .label rect,#mermaid-svg-6utkKi8N0YfmnN17 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6utkKi8N0YfmnN17 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-6utkKi8N0YfmnN17 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-6utkKi8N0YfmnN17 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 部署方式
JVM 运行时
Native Image 运行时
JAR + Docker
Native Executable + Docker
Native Executable 直接运行
20.2 代码对照
dockerfile
# ASP.NET Core Dockerfile(IoT 设备监控服务)
FROM mcr.microsoft.com/dotnet/aspnet:8.0
COPY bin/Release/net8.0/publish/ /app/
WORKDIR /app
EXPOSE 8080
ENTRYPOINT ["dotnet", "IotMonitor.dll"]
dockerfile
# Spring Boot Dockerfile(IoT 设备监控服务)
FROM eclipse-temurin:17-jre-alpine
COPY target/iot-monitor-1.0.0.jar /app.jar
WORKDIR /app
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]
20.3 启动命令对照
| 功能 | ASP.NET Core | Spring Boot |
|---|---|---|
| 开发模式 | dotnet run |
mvn spring-boot:run |
| 生产模式 | dotnet MyApp.dll |
java -jar MyApp.jar |
| 端口 | ASPNETCORE_URLS=http://+:8080 |
--server.port=8080 |
| 配置 | --environment=Production |
--spring.profiles.active=prod |
| JVM 参数 | 不适用 | -Xms512m -Xmx2g -XX:+UseG1GC |
| .NET 8 简化 | applicationUrl=http://+:8080(launchSettings.json) |
--- |
.NET 8 简化配置说明 :
launchSettings.json里的applicationUrl字段可直接声明绑定地址(含通配符+),等价于ASPNETCORE_URLS环境变量。开发期在 IDE /dotnet run中自动生效,生产期仍用环境变量或appsettings.json。
端口选型说明 :IoT 平台设备接入网关统一用 8080 (避免与 80 冲突,方便非 root 启动);停车场管理后台用 8081 ;监控服务用 8082 ;MQTT Broker 桥接器用 1883 (MQTT 标准端口);CoAP 接入用 5683(CoAP 标准端口)。
20.4 IoT 平台场景:3 万设备 + 4 微服务部署
| 微服务 | K8s Pod 数 | 节点副本 | 端口 | 镜像仓库 |
|---|---|---|---|---|
| iot-auth 设备鉴权 | 4 Pod | 4 节点 | 8080 | 阿里云 ACR cn-shanghai |
| iot-monitor 设备监控 | 8 Pod | 8 节点 | 8080 | 阿里云 ACR cn-shanghai |
| iot-ota OTA 升级 | 2 Pod | 2 节点 | 8080 | 阿里云 ACR cn-shanghai |
| iot-protocol 协议适配 | 6 Pod | 6 节点 | 8080/1883/5683 | 阿里云 ACR cn-shanghai |
- 镜像推阿里云 ACR(cn-shanghai 区域)
- K8s 集群 4 节点(每节点 8C 16G)
- 协议适配服务单独配
hostNetwork: true复用节点网络栈,避免 3 万长连接耗尽 SNAT - 监控服务 HPA 配置:CPU > 60% 自动扩容到 16 Pod,心跳接口 P99 延迟稳定在 50ms 内
20.5 4 车道 + 5 微服务部署
| 微服务 | K8s Pod 数 | 节点副本 | 端口 | 数据库 |
|---|---|---|---|---|
| parking-gate 出入口 | 4 Pod | 2 节点 × 2 副本 | 8080 | 写 MySQL 主库 |
| parking-order 订单 | 2 Pod | 2 节点 | 8080 | 写 MySQL 主库 |
| parking-billing 计费 | 2 Pod | 2 节点 | 8080 | 只读 MySQL 从库 |
| parking-pay 支付 | 2 Pod | 2 节点 | 8080 | 写 MySQL 主库 |
| parking-admin 监控 | 1 Pod | 1 节点 | 8080 | Prometheus + Grafana |
- 数据库 1 主 2 从(MySQL 8.0 / MHA 高可用)
- 出入口服务通过 nodeAffinity 绑定到 2 个固定节点(车牌识别摄像头 USB 加密狗直连物理节点)
- 支付服务对接支付宝 / 微信回调,Pod 暴露 8080 给内网 SLB
- 日志接入阿里云 SLS,链路追踪接入阿里云 ARMS
20.6 FAQ
- Q1:JVM 参数 -Xms / -Xmx / -Xmn 区别?
-Xms初始堆大小、-Xmx最大堆大小、-Xmn年轻代大小。生产环境强制-Xms = -Xmx,避免堆动态扩容带来的 STW 抖动(堆从 4G 扩到 8G 时所有线程暂停)。 - Q2:Docker 镜像如何瘦身?
三个手段:① multi-stage build(构建阶段用 maven:3.9-eclipse-temurin-17,运行阶段用 eclipse-temurin:17-jre-alpine);② 基础镜像选 Alpine 变体(170 MB → 60 MB);③ 合并 RUN 层、清理 apt-get 缓存。IoT 协议适配镜像从 480 MB 压缩到 95 MB。 - Q3:K8s HPA(Horizontal Pod Autoscaler)配置?
基于 CPU / 内存 / 自定义指标(QPS / 队列积压)自动扩缩容。典型配置:minReplicas: 2 / maxReplicas: 16 / metrics: cpu > 60%。需要先部署 Metrics Server / Prometheus Adapter。 - Q4:Spring Boot 优雅停机(SIGTERM)?
server.shutdown=graceful+spring.lifecycle.timeout-per-shutdown-phase=30s;K8s 配preStop钩子先从 Service Endpoints 摘除流量再 SIGTERM,避免 K8s 滚动更新时正在处理的请求被强杀。