ASP.NET Core 迁移至 Spring系列:编译生态篇

本文档是《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 CoreNuGet.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.xmlmirror 拦截所有中央仓库请求,统一走公司私服,下载速度从公网 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 滚动更新时正在处理的请求被强杀

相关推荐
Java技术小馆1 小时前
AI 如何理解对话
后端
小满zs1 小时前
Go语言第五章(数组和切片)
后端·go
AskHarries2 小时前
RSS 有必要做吗
后端
颜进强2 小时前
前端看后端 14:什么是 CORS?
前端·后端
Jul1en_2 小时前
【Java 脚手架】封装通用工具类-1
java·spring boot·分布式·spring·spring cloud
关于不上作者榜就原神启动那件事3 小时前
从 MDC 到 Agent:我手搓的文档路由协议,在 Spring AI Alibaba 里找到了正式实现
java·人工智能·spring·ai·agent
用户69371750013843 小时前
了解一下 Agent Harness
android·前端·后端
swipe3 小时前
16|(前端转全栈)前端人排查后端问题:curl、traceId、日志、MySQL、Redis 怎么用?
前端·后端·面试
亦暖筑序3 小时前
重新认识 AgentScope-Java 2.0:ReActAgent 负责推理,HarnessAgent 负责运行
java·后端·agent