# SpringCloud创建指南 **Repository Path**: homeless20/spring-cloud-creation-guide ## Basic Information - **Project Name**: SpringCloud创建指南 - **Description**: SpringCloud快速上手(有SpringBoot基础后) - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-25 - **Last Updated**: 2026-06-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Spring Cloud 微服务项目创建指南 > 基于 Spring Boot 3.4.x + Spring Cloud 2024.0.x,适合零基础快速上手。 --- ## 目录 1. [项目架构总览](#1-项目架构总览) 2. [技术栈与版本选型](#2-技术栈与版本选型) 3. [项目目录结构](#3-项目目录结构) 4. [第一步:创建父工程 POM](#4-第一步创建父工程-pom) 5. [第二步:创建公共模块 common](#5-第二步创建公共模块-common) 6. [第三步:创建服务注册中心 Eureka](#6-第三步创建服务注册中心-eureka) 7. [第四步:创建服务提供者 Provider](#7-第四步创建服务提供者-provider) 8. [第五步:创建服务消费者 Consumer (Feign)](#8-第五步创建服务消费者-consumer-feign) 9. [第六步:创建 API 网关 Gateway](#9-第六步创建-api-网关-gateway) 10. [启动与测试](#10-启动与测试) 11. [核心概念速查](#11-核心概念速查) 12. [常见问题与解决方案](#12-常见问题与解决方案) --- ## 1. 项目架构总览 ``` ┌─────────────────────┐ │ 外部客户端/浏览器 │ └──────────┬──────────┘ │ 全部请求发往 :8080 ▼ ┌─────────────────────┐ │ API 网关 Gateway │ │ (端口 8080) │ │ 路由 + 负载均衡 │ └──────┬──────┬───────┘ │ │ ┌────────────┘ └────────────┐ ▼ ▼ ┌──────────────────┐ ┌──────────────────┐ │ Consumer 消费者 │ │ Provider 提供者 │ │ 订单服务 :8082 │──Feign 调用──▶│ 用户服务 :8081 │ │ (调用用户服务) │ │ (提供用户 API) │ └────────┬─────────┘ └────────┬─────────┘ │ │ │ 注册 / 发现 │ └────────┐ ┌────────────┘ ▼ ▼ ┌──────────────────────────┐ │ Eureka 注册中心 :8761 │ │ 服务注册 / 服务发现 │ └──────────────────────────┘ ``` **五个模块各自职责:** | 模块 | 端口 | 角色 | 核心能力 | |---|---|---|---| | `spring-cloud-common` | - | 公共库 | 统一返回结果、DTO 定义 | | `spring-cloud-eureka` | 8761 | 注册中心 | 服务注册/发现、健康检查 | | `spring-cloud-gateway` | 8080 | API 网关 | 路由转发、负载均衡、统一入口 | | `spring-cloud-provider` | 8081 | 服务提供者 | 提供用户 CRUD API | | `spring-cloud-consumer` | 8082 | 服务消费者 | 通过 Feign 调用 Provider | --- ## 2. 技术栈与版本选型 **版本匹配是 Spring Cloud 项目中最容易踩坑的地方。** Spring Cloud 与 Spring Boot 有严格的版本对应关系: | Spring Cloud 版本 | 对应的 Spring Boot 版本 | |---|---| | 2024.0.x (Moorgate) | 3.4.x | | 2023.0.x (Leyton) | 3.3.x | | 2022.0.x (Kilburn) | 3.0.x / 3.1.x | 本项目的选择: | 组件 | 版本 | 说明 | |---|---|---| | Java | 17 | Spring Boot 3.x 最低要求 | | Spring Boot | 3.4.6 | 基础框架,内嵌 Tomcat | | Spring Cloud | 2024.0.1 | 微服务全家桶 | | Eureka | 内嵌在 Cloud 中 | 服务注册与发现 | | OpenFeign | 内嵌在 Cloud 中 | 声明式 HTTP 调用 | | Gateway | 内嵌在 Cloud 中 | 响应式 API 网关 | | LoadBalancer | 内嵌在 Cloud 中 | 客户端负载均衡 | **关键 Maven 概念:** ```xml ... ... ``` --- ## 3. 项目目录结构 ``` Spring_Cloud_Test/test1/ │ ├── pom.xml # 【父工程 POM】统一版本管理 │ ├── spring-cloud-common/ # 【公共模块 - 纯 JAR 库】 │ ├── pom.xml │ └── src/main/java/com/example/springcloud/common/ │ ├── dto/ │ │ └── UserDto.java # 用户数据传输对象 │ └── result/ │ └── Result.java # 统一返回结果封装 │ ├── spring-cloud-eureka/ # 【服务注册中心】 │ ├── pom.xml │ └── src/main/ │ ├── java/.../eureka/ │ │ └── EurekaServerApplication.java │ └── resources/ │ └── application.yml │ ├── spring-cloud-gateway/ # 【API 网关】 │ ├── pom.xml │ └── src/main/ │ ├── java/.../gateway/ │ │ └── GatewayApplication.java │ └── resources/ │ └── application.yml │ ├── spring-cloud-provider/ # 【服务提供者 - 用户服务】 │ ├── pom.xml │ └── src/main/ │ ├── java/.../provider/ │ │ ├── ProviderApplication.java │ │ ├── entity/ │ │ │ └── User.java # 用户实体 │ │ ├── controller/ │ │ │ └── UserController.java │ │ └── service/ │ │ ├── UserService.java │ │ └── impl/ │ │ └── UserServiceImpl.java │ └── resources/ │ └── application.yml │ └── spring-cloud-consumer/ # 【服务消费者 - 订单服务】 ├── pom.xml └── src/main/ ├── java/.../consumer/ │ ├── ConsumerApplication.java │ ├── controller/ │ │ └── OrderController.java │ ├── service/ │ │ ├── OrderService.java │ │ └── impl/ │ │ └── OrderServiceImpl.java │ ├── feign/ │ │ └── UserFeignClient.java # ★ Feign 接口(核心) │ └── fallback/ │ └── UserFeignFallback.java # 服务降级 └── resources/ └── application.yml ``` --- ## 4. 第一步:创建父工程 POM **作用:** 统一管理所有子模块的依赖版本,避免版本冲突。 **文件:** `pom.xml`(项目根目录) ### 4.1 核心要素 ```xml 4.0.0 com.example spring-cloud-demo 1.0.0 pom spring-cloud-common spring-cloud-eureka spring-cloud-gateway spring-cloud-provider spring-cloud-consumer 17 3.4.6 2024.0.1 org.springframework.boot spring-boot-dependencies ${spring-boot.version} pom import org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import org.projectlombok lombok true ``` ### 4.2 关键知识点 **`import` 的作用:** Spring Boot 和 Spring Cloud 都提供了自己的 BOM(Bill of Materials),用 `scope=import` 导入后,你引入它们的依赖时就不需要写版本号,版本由 BOM 统一管理。例如引入 `spring-boot-starter-web` 时无需写 ``。 **⚠️ 什么东西不该放在父 POM 的 `` 里?** - `spring-boot-starter-web`(Servlet MVC)—— 因为 Gateway 模块需要的是 WebFlux,两者冲突 - 只在部分模块使用的依赖——应该由各子模块自行声明 **⚠️ 最容易出现的错误:** 父 POM 统一引入 `spring-boot-starter-web` → Gateway 模块报错 `Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway`。解决方案:将 web 依赖从父 POM 移除,让 provider 和 consumer 各自引入。 --- ## 5. 第二步:创建公共模块 common **作用:** 存放所有微服务共用的代码,避免代码重复。 ### 5.1 POM 配置 ```xml com.example spring-cloud-demo 1.0.0 spring-cloud-common jar ``` ### 5.2 统一返回结果 `Result.java` ```java @Data @NoArgsConstructor @AllArgsConstructor public class Result { private int code; // 200 = 成功,其他 = 失败 private String message; // 提示信息 private T data; // 泛型数据 // 快速构建成功/失败响应 public static Result ok(T data) { return new Result<>(200, "success", data); } public static Result fail(int code, String message) { return new Result<>(code, message, null); } } ``` **设计原则:** - 所有 Controller 返回 `Result`,前端收到统一格式的 JSON - 泛型 `` 支持返回任意类型的数据 - 静态工厂方法 `Result.ok(data)` 比 `new Result(...)` 更语义化 ### 5.3 DTO(数据传输对象) DTO 与 Entity 的区别: - **Entity**:与数据库表对应,不能随意修改 - **DTO**:只包含需要传输的字段,解耦前后端和微服务之间 --- ## 6. 第三步:创建服务注册中心 Eureka **作用:** 所有微服务把地址注册到这里,调用方从这里发现目标服务。 **比喻:** 电话黄页 —— 公司注册号码,需要联系时先查黄页。 ### 6.1 POM 依赖 ```xml org.springframework.cloud spring-cloud-starter-netflix-eureka-server ``` ### 6.2 启动类 ```java @SpringBootApplication @EnableEurekaServer // ★ 关键注解:启动 Eureka 注册中心 public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } } ``` ### 6.3 配置文件 ```yaml server: port: 8761 # Eureka 默认端口 spring: application: name: eureka-server # 服务名称 eureka: client: register-with-eureka: false # ★ 自己就是注册中心,不注册自己 fetch-registry: false # ★ 不从自己拉取服务列表 service-url: defaultZone: http://localhost:8761/eureka/ server: enable-self-preservation: false # 开发环境关闭自我保护 ``` ### 6.4 验证方式 启动后访问 `http://localhost:8761`,看到 Eureka 控制台即表示成功。 --- ## 7. 第四步:创建服务提供者 Provider **作用:** 提供具体的业务 API,并注册到 Eureka。 ### 7.1 POM 依赖 ```xml org.springframework.cloud spring-cloud-starter-netflix-eureka-client org.springframework.boot spring-boot-starter-web com.example spring-cloud-common ``` ### 7.2 启动类 ```java @SpringBootApplication @EnableDiscoveryClient // 开启服务发现(注册到 Eureka) public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } } ``` ### 7.3 配置文件 ```yaml server: port: 8081 spring: application: name: user-service # ★ 服务名:这名字很重要,Consumer 用这个名字调用 eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ ``` ### 7.4 Controller 示例 ```java @RestController @RequestMapping("/user") public class UserController { @GetMapping("/{id}") public Result getUserById(@PathVariable Long id) { User user = userService.getUserById(id); if (user == null) { return Result.fail(404, "用户不存在"); } return Result.ok(convertToDto(user)); } } ``` --- ## 8. 第五步:创建服务消费者 Consumer (Feign) **作用:** 通过 OpenFeign 声明式调用 Provider,演示微服务间通信。 **这是 Spring Cloud 最重要的学习点之一。** ### 8.1 POM 依赖 ```xml org.springframework.cloud spring-cloud-starter-netflix-eureka-client org.springframework.cloud spring-cloud-starter-openfeign org.springframework.cloud spring-cloud-starter-loadbalancer ``` ### 8.2 启动类 ```java @SpringBootApplication @EnableDiscoveryClient @EnableFeignClients(basePackages = "com.example.springcloud.consumer.feign") // ★ public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } } ``` ### 8.3 Feign 接口(核心) ```java @FeignClient( name = "user-service", // ★ 目标服务名 = Provider 的 spring.application.name path = "/user", // 公共路径前缀 fallback = UserFeignFallback.class // 降级类 ) public interface UserFeignClient { @GetMapping("/{id}") // 等价于调用 GET http://user-service/user/{id} Result getUserById(@PathVariable("id") Long id); @GetMapping("/list") Result> listAllUsers(); } ``` **Feign 调用背后发生了什么?** ``` 1. Consumer 调用 userFeignClient.getUserById(1L) │ 2. Feign 动态代理拦截调用 │ 3. 根据 name="user-service" 去 Eureka 查询服务实例列表 │ 4. LoadBalancer 通过轮询算法选择一个实例(如 192.168.1.5:8081) │ 5. 拼装 URL:GET http://192.168.1.5:8081/user/1 │ 6. 发送 HTTP 请求,获取 JSON 响应 │ 7. 将 JSON 反序列化为 Result 返回 ``` **你不需要写一行 HTTP 调用代码!这就是"声明式调用"的含义。** ### 8.4 服务降级 Fallback(容错) ```java @Component public class UserFeignFallback implements UserFeignClient { @Override public Result getUserById(Long id) { return Result.fail(503, "用户服务暂时不可用(已降级)"); } } ``` 当 Provider 宕机或超时,不会直接报 500 错误给用户,而是返回降级后的友好提示,防止雪崩效应。 ### 8.5 配置文件 ```yaml server: port: 8082 spring: application: name: order-service eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ ``` --- ## 9. 第六步:创建 API 网关 Gateway **作用:** 所有外部请求的统一入口,将请求路由到对应的微服务。 ### 9.1 ⚠️ Gateway 最关键的问题 **Gateway 基于 WebFlux(响应式),与 spring-boot-starter-web(Servlet MVC)冲突!** - 父 POM 不要引入 `spring-boot-starter-web` - Gateway 自己的 POM 也不要引入 - `spring-cloud-starter-gateway` 自带 WebFlux ### 9.2 POM 依赖 ```xml org.springframework.cloud spring-cloud-starter-gateway org.springframework.cloud spring-cloud-starter-netflix-eureka-client ``` ### 9.3 启动类 ```java @SpringBootApplication @EnableDiscoveryClient public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } } ``` ### 9.4 路由配置(核心) ```yaml spring: cloud: gateway: routes: # --- 路由规则 1:用户服务 --- - id: user-service-route uri: lb://user-service # lb = Load Balance,服务名必须在 Eureka 中存在 predicates: - Path=/api/user/** # 匹配 /api/user/xxx 的请求 filters: - StripPrefix=1 # 去掉 /api,/api/user/1 → /user/1 转发 # --- 路由规则 2:订单服务 --- - id: order-service-route uri: lb://order-service predicates: - Path=/api/order/** filters: - StripPrefix=1 ``` **路由规则解读:** | 客户端请求 | 匹配的路由 | 去掉前缀后 | 实际转发到 | |---|---|---|---| | `/api/user/1` | user-service-route | `/user/1` | `lb://user-service/user/1` | | `/api/user/list` | user-service-route | `/user/list` | `lb://user-service/user/list` | | `/api/order/create` | order-service-route | `/order/create` | `lb://order-service/order/create` | --- ## 10. 启动与测试 ### 10.1 启动顺序(重要!) ``` 第 1 步:启动 spring-cloud-eureka —— 注册中心必须先启动 第 2 步:启动 spring-cloud-provider —— 服务提供者注册到 Eureka 第 3 步:启动 spring-cloud-consumer —— 服务消费者注册到 Eureka 第 4 步:启动 spring-cloud-gateway —— 网关最后启动,接收外部请求 ``` ### 10.2 启动命令 ```bash # 在项目根目录(test1/)执行 # 方式一:一次编译全部模块 mvn clean package -DskipTests # 方式二:分别启动各模块 cd spring-cloud-eureka && mvn spring-boot:run & cd spring-cloud-provider && mvn spring-boot:run & cd spring-cloud-consumer && mvn spring-boot:run & cd spring-cloud-gateway && mvn spring-boot:run & ``` ### 10.3 验证各组件 | 验证内容 | 访问地址 | 预期结果 | |---|---|---| | Eureka 控制台 | `http://localhost:8761` | 看到 3 个服务:GATEWAY, USER-SERVICE, ORDER-SERVICE | | Provider 直连 | `http://localhost:8081/user/1` | 返回用户张三的信息 | | Consumer 直连 | `http://localhost:8082/order/user/1` | 通过 Feign 获取用户张三 | | Consumer 创建订单 | `POST http://localhost:8082/order/create?userId=1&productName=iPhone` | 返回订单 + 用户信息 | | 网关 → 用户服务 | `http://localhost:8080/api/user/1` | 经网关路由到 user-service | | 网关 → 订单服务 | `http://localhost:8080/api/order/user/1` | 经网关路由到 order-service | | Feign 降级测试 | 停掉 Provider 后访问 Consumer | 返回 503 + 降级提示 | ### 10.4 测试调用链 ```bash # 最完整的调用链:浏览器 → 网关 → 消费者 → Feign → 提供者 curl "http://localhost:8080/api/order/create?userId=1&productName=iPhone" # 返回示例: { "code": 200, "message": "success", "data": { "success": true, "orderId": 1719345678000, "productName": "iPhone", "user": { "id": 1, "username": "张三", "email": "zhangsan@example.com", "phone": "13800000001" } } } ``` **这个调用经历了:** ``` 浏览器 → Gateway (路由匹配 + 负载均衡) → order-service (Consumer) → Feign (声明式调用) → Eureka (服务发现 + 负载均衡) → user-service (Provider 返回数据) ``` --- ## 11. 核心概念速查 ### 11.1 服务注册与发现 ``` Provider 启动 → 向 Eureka 注册自己的 IP:端口 → Consumer 从 Eureka 查到 Provider 地址 → 发起调用 ``` - **注册:** 服务启动时告诉 Eureka "我在这里,IP 是 X,端口是 Y" - **发现:** 调用方从 Eureka 获取目标服务的实例列表 - **心跳:** 服务每 30 秒向 Eureka 发一次心跳,Eureka 90 秒收不到心跳就剔除该服务 ### 11.2 OpenFeign 声明式调用 | 传统方式 | Feign 方式 | |---|---| | `RestTemplate.getForObject("http://192.168.1.5:8081/user/1", ...)` | `userFeignClient.getUserById(1L)` | | 需要自己写 URL,硬编码 IP 和端口 | 只需写接口 + 注解,Feign 自动生成实现 | | 需要自己处理负载均衡 | 自动集成 LoadBalancer | | 需要自己序列化/反序列化 JSON | 自动处理 | ### 11.3 负载均衡 客户端负载均衡(Spring Cloud LoadBalancer): 1. 从 Eureka 拿到 Provider 的所有实例:`[192.168.1.5:8081, 192.168.1.6:8081, 192.168.1.7:8081]` 2. 通过轮询算法选择一个实例 3. 将请求发送到选中的实例 4. 下次请求选下一个实例(轮询) ### 11.4 API 网关 网关 = 小区的门卫,所有访客(请求)都要经过门卫: - **路由:** 根据路径将请求分发到对应的服务 - **统一鉴权:** 在网关层做登录验证,不需要每个服务都验证一遍 - **跨域处理:** 在网关统一处理 CORS - **限流:** 控制请求频率,防止服务被打垮 ### 11.5 服务降级与熔断 | 概念 | 说明 | 类比 | |---|---|---| | **降级 (Fallback)** | 被调服务不可用时,返回兜底结果 | 餐厅某道菜卖完了,推荐你另一道菜 | | **熔断 (Circuit Breaker)** | 错误率达到阈值时,直接切断调用,快速失败 | 保险丝过载断开,防止火灾 | | **限流 (Rate Limit)** | 控制单位时间内的请求数量 | 景区限流,每天只卖 3 万张票 | --- ## 12. 常见问题与解决方案 ### 12.1 Gateway 报错:Spring MVC incompatible **错误信息:** ``` Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway. ``` **原因:** 父 POM 或 Gateway 模块引入了 `spring-boot-starter-web`(Servlet MVC),与 Gateway 的 WebFlux 冲突。 **解决:** 1. 父 POM 不引入 `spring-boot-starter-web` 2. 让 Provider 和 Consumer 各自引入 3. Gateway 只用 `spring-cloud-starter-gateway`(自带 WebFlux) ### 12.2 Eureka 上看到服务但 Feign 调用失败 **可能原因:** - 服务名大小写不一致(Eureka 将服务名转为大写,但 Feign 的 name 区分大小写) - Feign 接口的 `@RequestMapping` 路径与 Provider 的路径不匹配 - 未引入 `spring-cloud-starter-loadbalancer` ### 12.3 Feign 超时 Feign 默认超时时间很短(约 1 秒),复杂业务容易超时: ```yaml spring.cloud.openfeign.client.config.default: connect-timeout: 5000 # 连接超时 5 秒 read-timeout: 5000 # 读取超时 5 秒 ``` ### 12.4 Eureka 自我保护机制 Eureka 控制台出现红色警告 `EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP...` 这是 Eureka 的自我保护机制:短时间内大量服务心跳丢失时,Eureka 不会立即剔除它们,防止因网络波动误删健康服务。 开发环境建议关闭:`eureka.server.enable-self-preservation: false` --- ## 附:版本对应关系速查表 | Spring Boot | Spring Cloud | Java | 备注 | |---|---|---|---| | 3.5.x | 2025.0.x | 17+ | 最新版 | | 3.4.x | 2024.0.x | 17+ | 本项目使用 | | 3.3.x | 2023.0.x | 17+ | 上一代 | | 3.0.x-3.1.x | 2022.0.x | 17+ | - | | 2.7.x | 2021.0.x | 8/11 | 大量存量项目 | | 2.3.x-2.4.x | Hoxton | 8 | 已停止维护 | --- > **学习建议:** > 1. 按启动顺序依次启动各模块,逐个验证 > 2. 在 Controller 中打断点,观察调用链 > 3. 停掉 Provider 模拟故障,观察 Feign 降级效果 > 4. 在 Eureka 控制台观察服务的上线/下线 > 5. 尝试新增一个服务,练习 Feign 调用和 Gateway 路由配置