【Spring Cloud】微服务
1.Spring Cloud概述
1.1.集群和分布式
集群: 将⼀个系统完整的部署到多个服务器上, 每个服务器都能提供系统的所有服务, 多个服务器通过负载均衡调度完成任务., 每个服务器称为集群的节点
分布式: 将⼀个系统拆分为多个子系统,多个子系统部署在多个服务器上,多个服务器上的子系统协同合作完成⼀个特定任务.
1.2.微服务简介
微服务, 就是一种经过良好架构设计的分布式架构方案, 其将系统拆分为更细粒度的服务,每个服务只负责一个单一功能,服务独立部署和运行,并通过轻量级协议(如REST或RPC)进行通信
1.3.Spring Cloud简介
Spring Cloud 是分布式微服务架构的一站式解决方案, 是微服务架构落地的多种技术的集
合, 通过整合多种开源技术,提供了一套工具集来简化微服务开发中的常见问题处理
如:
- 分布式版本配置:管理不同环境下的配置
- 服务注册和发现:自动注册和发现服务实例
- 路由:智能路由请求到目标服务
- 服务调用:简化服务间的通信
- 负载均衡:分配请求负载,提高系统稳定性
- 断路器:防止故障扩散,提升系统韧性
- 分布式消息:处理异步消息传递
2.拆分原则
2.1.单⼀职责
⼀个微服务应该只负责⼀个功能或业务领域, 每个服务应该有清晰的定义和边界, 只
关注自己的特定业务领域.
2.2.服务自治
每个微服务都应该具备⾼度自治的能力, 每个服务要能做到独立开发, 独立测试, 独立构
建, 独立部署, 独立运行
2.3.单向依赖
微服务之间需要做到单向依赖, 严禁循环依赖, 双向依赖
循环依赖: A -> B -> C ->A
双向依赖: A -> B, B -> A
3.服务注册与服务发现
3.1.注册中心
注册中心可以维护⼀个服务列表, 哪个机器上线了, 哪个机器宕机了, 这些信息都会自动更新到服务列表上, 客户端拿到这个列表时可以直接进行服务调用
注册中心主要有三种角色:
• 服务提供者:⼀次业务中, 被其它微服务调用的服务. 也就是提供接口给其它微服务.
• 服务消费者:⼀次业务中, 调用其它微服务的服务. 也就是调用其它微服务提供的接口.
• 服务注册中心: 用于保存Server 的注册信息, 当Server 节点发生变更时, Registry 会同步变更. 服务与注册中心使用⼀定机制通信, 如果注册中心与某服务长时间无法通信, 就会注销该实例
他们之间的关系以及工作内容, 可以通过两个概念来描述:
服务注册:服务提供者在启动时, 向 Registry 注册自身服务, 并向 Registry 定期发送心跳汇报存活状态.
服务发现:服务消费者从注册中心查询服务提供者的地址,并通过该地址调用服务提供者的接口, 从而提供给服务消费者⼀个可用的服务列表
服务启动/变更时, 向注册中心报道. 注册中心记录应用和IP的关系.
调用方调用时, 先去注册中心获取服务方的IP, 再去服务方进行调用
3.2.CAP
• ⼀致性:CAP理论中的⼀致性, 指的是强⼀致性. 所有节点在同⼀时间具有相同的数据
• 可用性:保证每个请求都有响应(响应结果可能不对)
• 分区容错性:当出现网络分区后,系统仍然能够对外提供服务
CAP 理论指出:分布式系统中最多同时满足两个特性,由于网络分区不可避免,所以注册中心只有CA、CP两种架构:
CP架构:优先保证数据一致性(C),但可能牺牲可用性(A)。例如,在网络异常时,拒绝请求以维护数据一致
AP架构:优先保证可用性(A),但可能返回不一致的数据。例如,在网络异常时,返回缓存数据(即使旧版本也一样),确保服务不中断
4.负载均衡
负载均衡(Load Balance,简称 LB) , 是高并发, 高可用系统必不可少的关键组件
当服务流量增大时, 将请求流量合理分配到多个资源(如服务器实例)

4.1.Spring Cloud LoadBalancer
@Configuration
public class BeanConfig {@LoadBalanced@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}
public OrderInfo selectOrderById(Integer id) {OrderInfo orderInfo = orderMapper.selectOrderById(id);String url = "http://product-service/product/" + orderInfo.getProductId(); ProductInfo product = restTemplate.getForObject(url, ProductInfo.class);orderInfo.setProductInfo(product);return orderInfo;}
4.1.2.负载均衡策略
4.1.3.自定义负载均衡策略
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;public class LoadBalancerConfig {@BeanReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,LoadBalancerClientFactory loadBalancerClientFactory) {String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);System.out.println("==============" + name);return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),name);}
}
@LoadBalancerClient(name = "product-service", configuration = LoadBalancerConfig.class)
@Configuration
public class BeanConfig {@Bean@LoadBalancedpublic RestTemplate restTemplate() {return new RestTemplate();}
}
5.Nacos
5.1 引入依赖
在父工程的pom文件中的 <dependencyManagement> 中引入Spring Cloud Alibaba的依赖
<properties><spring-cloud-alibaba.version>2022.0.0.0-RC2</spring-cloud-alibaba.version>
</properties>
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring-cloud-alibaba.version}</version><type>pom</type><scope>import</scope>
</dependency>
在子工程中引入 Nacos 和 Load Balance 依赖
// alibaba 依赖
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
// Load Balance 依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
Nacos的对应服务中配置子工程 yml
spring:application:name: order-servicecloud:nacos:discovery:server-addr: 127.0.0.1:8848
配置服务器代码
@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate RestTemplate restTemplate;public OrderInfo selectOrderById(Integer id) {OrderInfo orderInfo = orderMapper.selectOrderById(id);System.out.println(orderInfo.getProductId());String url = "http://product-service/product/" + orderInfo.getProductId();ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);orderInfo.setProductInfo(productInfo);return orderInfo;}
}
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;@Configuration
public class BeanConfig {@Bean@LoadBalancedpublic RestTemplate restTemplate() {return new RestTemplate();}
}
启动两个服务, 观察Nacos的管理界面 发现两个服务都注册在Nacos上了
5.2.权重配置

5.3 开启Nacos负载均衡策略
# 开启Nacos的负载均衡策略
spring:cloud:loadbalancer:nacos:enabled: true
5.4.Nacos 健康检查
5.4.1.两种健康检查机制

5.4.2.Nacos服务实例类型
5.5.Nacos环境隔离

切勿忘记, 也要在idea上修改此服务在nacos上的命名空间
spring:cloud:nacos:config:namespace: xxxxxx
5.6.Nacos配置中心


<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency><!-- SpringCloud 2020.*之后版本需要引入bootstrap -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
6.OpenFeign
6.1 Spring Cloud Feign
引入依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;@EnableFeignClients
@SpringBootApplication
public class OrderServiceApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class, args);}
}
import com.bite.order.model.ProductInfo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(value = "product-service", path = "/product")
public interface ProductApi {@GetMapping("/{productId}")ProductInfo getProductById(@PathVariable("productId") Integer productId);
}
import org.springframework.beans.factory.annotation.Autowired;@Autowired
private ProductApi productApi;/*** Feign实现远程调用* @param orderId 订单ID* @return 包含商品信息的订单详情*/
public OrderInfo selectOrderById(Integer orderId) {OrderInfo orderInfo = orderMapper.selectOrderById(orderId);ProductInfo productInfo = productApi.getProductById(orderInfo.getProductId());orderInfo.setProductInfo(productInfo);return orderInfo;
}
6.2.Feign 抽取
在企业开发中,将Feign接口抽取为一个独立模块是常见做法。这能提高代码重用性、解耦服务提
供方和消费者,并简化维护
通过打 Jar 包放在本地 Maven 仓库的方式来模拟服务器之间的调度
服务消费方使用 product-api 依赖,并且指定启动类扫描 ProducApi 接口
@EnableFeignClients(clients = {ProductApi.class})
@SpringBootApplication
public class OrderServiceApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class, args);}
}
@RestController
@RequestMapping("/product")
public class ProductApiController {@Autowiredprivate ProductApi productApi;@RequestMapping("/{id}")ProductInfo getProductInfo(@RequestParam("id") Integer id) {return productApi.gerProductById(id);}@RequestMapping("/o1")public String returnId (@RequestParam("id") Integer id){return productApi.returnId(id);}@RequestMapping("/o2")public String returnId2 (@RequestParam("name") String name,@RequestParam("id") Integer id){return productApi.getNameAndId(id,name);}@RequestMapping("/o3")public String returnId3 (ProductInfo productInfo){return productApi.returnInfo(productInfo);}@RequestMapping("/o4")public String returnId4 (@RequestBody ProductInfo productInfo){return productApi.returnInfoJson(productInfo);}}
服务提供方:
@RestController
@RequestMapping("/product")
public class ProductController {@Autowiredpublic ProductService productService;@RequestMapping("/{productId}")public ProductInfo getProductById(@PathVariable("productId") Integer productId) {return productService.selectProductById(productId);}@RequestMapping("/p1")public String getProductByName1(Integer id,String name) {return "product-server 接收到参数 id = " + id + " name = " + name;}@RequestMapping("/p2")public String getProductByName(Integer id,String name) {return "product-server 接收到参数 id = " + id + " name = " + name;}@RequestMapping("/p3")public String getInfo (ProductInfo productInfo) {return productInfo.toString();}@RequestMapping("/p4")public String getInfoJson (@RequestBody ProductInfo productInfo) {return productInfo.toString();}
}
流程:
a)服务消费方 Controller 调用公共 productApi 接口
b)公共 productApi 接口处理请求, Feign 在运行时自动生成代理实现,将接口方法调用转换为 HTTP 请求。基于服务注册与发现 ,请求会被路由到服务器提供方的对应端点。
c)服务提供方的方法执行, Controller 接受 HTTP 请求并执行具体业务逻辑。地址的发现通过 HTTP 响应返回给服务消费方 Feign 客户端,然后再传到消费方 Controller 获取数据
URL 拼接过程:公共接口 @FeignClient.path + 公共接口方法的 URL = 要调用的 Controller 方法的 URL (服务提提供方的实际路径)
7.统⼀服务入口-Gateway

7.1.Spring Cloud Gateway
7.1.1.快速上手
创建网关项目
<!--⽹关--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!--基于nacos实现服务发现依赖--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--负载均衡--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>
server:port: 10030 # 网关端口spring:application:name: gateway # 服务名称cloud:nacos:discovery:server-addr: xxxxx # Nacos服务发现地址gateway:routes: # 网关路由配置- id: product-service # 路由ID,自定义,唯一即可uri: lb://product-service # 目标服务地址,lb表示负载均衡predicates: # 路由条件- Path=/product/**- id: order-service # 订单服务路由uri: lb://order-servicepredicates:- Path=/order/**
7.2.Gateway Filter Factories(网关过滤器工厂)

7.3 .GlobalFilter
GlobalFilter是Spring Cloud Gateway提供的一个接口,它允许开发者在所有路由请求上应用自定义逻辑。无论路由配置如何,GlobalFilter都会在请求处理链中被执行。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>
spring:cloud:gateway:metrics:enabled: true # 开启Gateway的指标收集功能(如请求计数、延迟等)
management:endpoints:web:exposure:include: "*" # 暴露所有管理端点(健康检查/指标/shutdown等)endpoint:health:show-details: always # 始终显示健康检查的详细信息(包括组件状态)shutdown:enabled: true # 启用应用关闭端点(可通过HTTP请求优雅停止服务)
7.3.1.过滤器执行顺序
在Spring Cloud Gateway中,当请求路由后,网关会将项目中的所有过滤器(包括GatewayFilter和GlobalFilter)合并到一个统一的过滤器链中,并按照特定的顺序执行。
过滤器链的合并与排序
网关在运行时,会将当前项目中的GatewayFilter和GlobalFilter合并到一个集合中。
这个集合会按照每个过滤器的 order 值进行排序。order 是一个 int 类型的属性,默认值为0。
排序规则是:order 值越小,优先级越高,执行顺序越靠前。
当order值相同时的执行优先级
如果多个过滤器的 order 值相等,网关会按照以下固定优先级顺序执行:
defaultFilter:网关的默认过滤器(优先级最高)。
GatewayFilter:用户定义的路由级过滤器。
GlobalFilter:全局过滤器(优先级最低)
7.4.自定义过滤器
7.4.1.自定义GatewayFilter
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;@Slf4j
@Service
public class CustomGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomGatewayFilterFactory.CustomConfig> implements Ordered {public CustomGatewayFilterFactory() {super(CustomConfig.class);}@Overridepublic GatewayFilter apply(CustomConfig config) {/*** Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)* ServerWebExchange: HTTP请求-响应交互的契约, 提供对HTTP请求和响应的访问, * 服务器端请求属性, 请求实例,响应实例等, 类似Context角色* GatewayFilterChain: 过滤器链* Mono: Reactor核心类, 数据流发布者, Mono最多只触发一个事件, * 所以可以把Mono用于在异步任务完成时发出通知.* Mono.fromRunnable: 创建一个包含Runnable元素的数据流*/return ((exchange, chain) -> {log.info("[Pre] Filter Request, name:" + config.getName());return chain.filter(exchange).then(Mono.fromRunnable(() -> {log.info("[Post] Response Filter");}));});}@Overridepublic int getOrder() {return Ordered.LOWEST_PRECEDENCE; // 配置优先级, order越大, 优先级越低}@Datapublic static class CustomConfig {private String name;}
}
7.4.2.⾃定义GlobalFilter
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;@Slf4j
@Service
public class CustomGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info("[Pre] CustomGlobalFilter enter...");return chain.filter(exchange).then(Mono.fromRunnable(() -> {log.info("[Post] CustomGlobalFilter return...");}));}@Overridepublic int getOrder() {return Ordered.LOWEST_PRECEDENCE; // 配置优先级, order越大, 优先级越低}
}