一、先搞懂:为什么需要 Spring Cloud?(微服务痛点)
单体应用(一个项目包含所有功能)的问题:代码臃肿、开发协作难、升级风险高、并发瓶颈明显。
微服务就是把单体应用拆成多个独立服务(如下单服务、用户服务、库存服务),但拆分后会出现新问题:
- 服务太多,怎么找到对方?(注册发现)
- 服务配置太多(数据库、端口等),怎么统一管理?(配置中心)
- 一个请求要调用多个服务,怎么简化调用?(远程调用)
- 多个服务实例,请求怎么分配?(负载均衡)
- 某个服务挂了,怎么避免连锁崩溃?(熔断降级)
- 所有服务入口不一样,怎么统一访问?(API 网关)
- 分布式系统中,怎么保证跨服务数据一致?(分布式事务)
二、Spring Cloud 核心组件(按使用优先级排序)
1. 服务注册与发现 — 解决「服务怎么找对方」
核心作用:所有服务启动后,自动注册到「注册中心」,其他服务通过注册中心获取目标服务的地址(IP + 端口),不用硬编码配置。
- 主流组件:Nacos(阿里开源,功能最全,推荐)、Eureka(Netflix 开源,简单轻量,已停更)。
工作流程:
- 下单服务启动 → 向 Nacos 注册自己的地址(如
192.168.1.100:8081); - 库存服务启动 → 也向 Nacos 注册自己的地址(如
192.168.1.101:8082); - 下单服务需要调用库存服务时,先向 Nacos 查询「库存服务的地址列表」;
- Nacos 返回库存服务的可用地址,下单服务直接调用。
实战配置(Nacos 为例):
1、引入依赖(Spring Boot 2.x 对应 Spring Cloud Alibaba 版本):
<!-- Nacos 服务注册发现依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.2.7.RELEASE</version> <!-- 版本需与 Spring Boot 匹配 --> </dependency>2、配置application.yml:
spring: application: name: order-service # 服务名称(注册到 Nacos 的唯一标识) cloud: nacos: discovery: server-addr: localhost:8848 # Nacos 服务器地址(本地启动的 Nacos) server: port: 8081 # 下单服务端口3、启动类加注解(开启服务注册发现):
@SpringBootApplication @EnableDiscoveryClient // 开启服务注册发现(Spring Cloud 通用注解,Nacos/Eureka 都支持) public class OrderServiceApplication { public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class, args); } }4、启动 Nacos 服务器(本地版):下载 Nacos 安装包,执行startup.cmd(Windows),访问http://localhost:8848/nacos(账号密码默认nacos/nacos),即可看到注册的服务。
2. 配置中心(Nacos Config)—— 解决「配置统一管理」
核心作用:把所有服务的配置(数据库、端口、自定义参数等)集中存储在 Nacos,支持「动态刷新」(改配置不用重启服务)、「多环境隔离」(开发 / 测试 / 生产配置分开)。
实战配置(Nacos Config 为例):
1、引入依赖:
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>2.2.7.RELEASE</version> </dependency>2、新建bootstrap.yml(优先级比application.yml高,用于加载 Nacos 配置):
spring: application: name: order-service cloud: nacos: config: server-addr: localhost:8848 # Nacos 地址 file-extension: yml # 配置文件格式(yml/properties) group: DEFAULT_GROUP # 配置分组(默认即可) profiles: active: dev # 激活开发环境配置3、在 Nacos 控制台添加配置:
- 配置 ID:
order-service-dev.yml(格式:服务名-环境名.文件格式); - 配置内容(数据库、自定义参数等):
spring: datasource: url: jdbc:mysql://localhost:3306/order_db?useSSL=false username: root password: 123456 myapp: notify: true # 自定义配置4、配置注入与动态刷新:
@Component @RefreshScope // 开启动态刷新(Nacos 配置修改后,自动更新注入值) public class OrderConfig { @Value("${myapp.notify}") private boolean notify; // getter/setter }- 效果:修改 Nacos 中的
myapp.notify为false,无需重启服务,OrderConfig中的notify会自动更新。
3. 远程调用(OpenFeign)—— 解决「服务间怎么调用」
核心作用:简化服务间 HTTP 调用(不用手动写客户端),支持负载均衡、熔断降级,且能和 Spring 无缝整合(注解式调用)。
实战配置(OpenFeign 为例):
1、引入依赖:
<!-- OpenFeign 依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.2.9.RELEASE</version> </dependency>2、启动类加注解(开启 Feign 功能):
@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients // 开启 OpenFeign public class OrderServiceApplication { public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class, args); } }3、定义 Feign 接口(映射库存服务的接口):
// 声明要调用的服务名称(Nacos 中注册的 stock-service 名称) @FeignClient(name = "stock-service") public interface StockFeignClient { // 映射库存服务的扣库存接口(和 stock-service 的 Controller 接口一致) @PostMapping("/stock/deduct") Result<Boolean> deductStock(@RequestBody StockDTO stockDTO); } // 库存服务的 DTO(和 stock-service 中的 DTO 完全一致) @Data public class StockDTO { private Long goodsId; private Integer num; }4、服务端(stock-service)的接口(被调用方):
@RestController @RequestMapping("/stock") public class StockController { @Autowired private StockService stockService; @PostMapping("/deduct") public Result<Boolean> deductStock(@RequestBody StockDTO stockDTO) { boolean success = stockService.deduct(stockDTO.getGoodsId(), stockDTO.getNum()); return Result.success(success); } }5、下单服务调用 Feign 接口:
@Service public class OrderServiceImpl implements OrderService { @Autowired private StockFeignClient stockFeignClient; @Autowired private OrderMapper orderMapper; @Transactional @Override public Order createOrder(OrderDTO dto) { // 1. 远程调用库存服务扣库存 StockDTO stockDTO = new StockDTO(); stockDTO.setGoodsId(dto.getGoodsId()); stockDTO.setNum(dto.getNum()); Result<Boolean> deductResult = stockFeignClient.deductStock(stockDTO); if (!deductResult.getData()) { throw new BusinessException("库存不足"); } // 2. 创建订单(本地事务) Order order = new Order(); order.setUserId(dto.getUserId()); order.setGoodsId(dto.getGoodsId()); orderMapper.insert(order); return order; } }- 效果:下单服务调用
StockFeignClient.deductStock(),Feign 会自动通过 Nacos 找到 stock-service 的地址,发起 HTTP 请求,且支持负载均衡(如果 stock-service 启动多个实例,会自动分发请求)。
4. API 网关(Spring Cloud Gateway)—— 解决「统一入口 + 路由转发」
核心作用:所有前端请求都通过网关进入,网关负责:路由转发(把请求转发到对应服务)、统一拦截(登录校验、权限控制、限流)、跨域处理等,不用每个服务都单独实现这些功能。
实战配置(Gateway 为例):
1、新建网关服务(独立的 Spring Boot 项目),引入依赖:
<!-- Gateway 依赖(注意:Gateway 基于 WebFlux,不能和 spring-boot-starter-web 共存) --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> <version>2.2.9.RELEASE</version> </dependency> <!-- Nacos 注册发现依赖(网关需要从 Nacos 获取服务地址) --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.2.7.RELEASE</version> </dependency>2、配置application.yml(路由规则):
spring: application: name: gateway-service # 网关服务名称 cloud: nacos: discovery: server-addr: localhost:8848 # Nacos 地址 gateway: routes: # 路由1:下单服务(/order/** 开头的请求转发到 order-service) - id: order-service-route uri: lb://order-service # lb=负载均衡,指向 Nacos 中的服务名 predicates: - Path=/order/** # 路径匹配规则 filters: - StripPrefix=1 # 去掉路径前缀(/order/deduct → /deduct,转发到 order-service) # 路由2:库存服务(/stock/** 开头的请求转发到 stock-service) - id: stock-service-route uri: lb://stock-service predicates: - Path=/stock/** filters: - StripPrefix=1 server: port: 8080 # 网关端口(前端统一访问 8080)3、启动类:
@SpringBootApplication @EnableDiscoveryClient public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } }- 前端访问
http://localhost:8080/order/create→ 网关转发到order-service的/create接口; - 前端访问
http://localhost:8080/stock/deduct→ 网关转发到stock-service的/deduct接口; - 所有请求都走网关,后续登录校验、限流等都可以在网关统一实现。
5. 熔断降级(Sentinel)—— 解决「服务雪崩」
核心作用:当某个服务(如库存服务)挂了或响应超时,调用方(下单服务)不会一直等待,而是快速返回「降级结果」(如 “当前库存服务繁忙,请稍后重试”),避免下单服务线程阻塞,进而导致整个系统崩溃(服务雪崩)。
- 主流组件:Sentinel(阿里开源,轻量、功能强,推荐)、Hystrix(Netflix 开源,已停更)。
实战配置(Sentinel 为例):
1、引入依赖(在下单服务中引入,因为是调用方需要熔断):
<!-- Sentinel 核心依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2.2.7.RELEASE</version> </dependency> <!-- Sentinel 与 OpenFeign 整合(对 Feign 调用进行熔断) --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-sentinel-feign</artifactId> <version>2.2.7.RELEASE</version> </dependency>2、配置application.yml:
spring: cloud: sentinel: transport: dashboard: localhost:8080 # Sentinel 控制台地址(本地启动的 Sentinel) port: 8719 # 与控制台通信的端口(默认即可) feign: sentinel: enabled: true # 开启 Feign 与 Sentinel 的整合(对 Feign 调用熔断)3、定义 Feign 降级类(服务熔断时返回的默认结果):
// 实现 StockFeignClient 接口,重写熔断时的方法 @Component public class StockFeignFallback implements StockFeignClient { @Override public Result<Boolean> deductStock(StockDTO stockDTO) { // 降级逻辑:返回失败,提示用户 return Result.fail("库存服务繁忙,请稍后重试"); } }4、修改 Feign 接口,指定降级类:
@FeignClient(name = "stock-service", fallback = StockFeignFallback.class) // 指定降级类 public interface StockFeignClient { @PostMapping("/stock/deduct") Result<Boolean> deductStock(@RequestBody StockDTO stockDTO); }5、启动 Sentinel 控制台(本地版):下载 Sentinel jar 包,执行java -jar sentinel-dashboard-1.8.6.jar,访问http://localhost:8080(账号密码默认sentinel/sentinel)。
- 效果:
- 当 stock-service 正常时,下单服务调用 Feign 接口正常返回;
- 当 stock-service 挂了或响应超时,Sentinel 触发熔断,调用
StockFeignFallback.deductStock(),返回 “库存服务繁忙,请稍后重试”,下单服务不会阻塞,系统正常运行。
三、其他重要组件(进阶必备)
1. 分布式事务(Seata)—— 解决「跨服务数据一致性」
- 问题:下单服务创建订单(本地事务),调用库存服务扣库存(远程事务),如果扣库存成功但下单服务后续抛异常,会出现「库存扣了但订单没创建」的不一致情况。
- 解决方案:Seata(阿里开源),支持「AT 模式」(无侵入,推荐),通过全局事务协调器保证跨服务事务的原子性(要么都成功,要么都回滚)。
2. 服务监控(Spring Cloud Actuator + Prometheus + Grafana)
- 作用:监控每个服务的运行状态(内存、CPU、接口耗时、异常数),通过 Grafana 可视化展示,方便运维排查问题。
3. 链路追踪(SkyWalking/Zipkin)—— 解决「跨服务调用排查」
- 问题:一个请求要调用多个服务(如前端→网关→下单服务→库存服务),如果出现错误,不知道是哪个服务的问题。
- 解决方案:SkyWalking,追踪整个调用链路,记录每个服务的执行时间、是否报错,快速定位问题所在。
4. 限流(Sentinel/Gateway 限流)—— 解决「高并发流量控制」
- 作用:限制某个接口的并发请求数(如下单接口每秒最多处理 100 个请求),避免高并发导致服务崩溃。