Spring Cloud 微服务项目中间件使用总结文档

1. Nacos 服务注册与发现中心

Nacos 配置中心

1.1 作用

  • 服务注册: 各微服务启动时自动注册到 Nacos
  • 服务发现: 服务间调用时从 Nacos 获取目标服务实例
  • 配置管理: 集中管理各服务的配置文件

1.2 Maven 依赖

<!-- Nacos 服务注册发现 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!-- Nacos 配置中心 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

1.3 核心注解

@SpringBootApplication
@EnableDiscoveryClient  // 启用服务发现功能
public class UserServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServerApplication.class, args);
    }
}

1.4 实际项目配置文件详解

用户服务 (user-server) 配置示例

bootstrap.yml 配置详解:

server:
  port: 8444 # 服务启动端口号,用于接收客户端请求

spring:
  application:
    name: user-server # 服务名称,用于在Nacos注册中心标识此服务
  cloud:
    nacos:
      config: # Nacos配置中心设置
        server-addr: 127.0.0.1:8848 # Nacos服务器地址和端口
        namespace: public # 命名空间,用于环境隔离(dev/test/prod)
        shared-configs: # 共享配置列表,多个服务可共用
          - data-id: mysql-shopuser.yaml # 数据库配置文件ID
            group: DEFAULT_GROUP # 配置分组,便于管理
            refresh: false # 是否开启配置自动刷新
          - data-id: nacos-discovery.yaml # 服务发现配置文件
            group: DEFAULT_GROUP
            refresh: false
          - data-id: seata-client.yaml # Seata分布式事务配置
            group: SEATA_GROUP # Seata专用分组
            refresh: false
        extension-configs: # 扩展配置列表,服务特有配置
          - data-id: sentinel-public.yaml # Sentinel流控配置文件
            group: DEFAULT_GROUP
            refresh: false

seata:
  application-id: ${spring.application.name} # Seata应用ID,覆盖Nacos中的配置

网关服务 (gateway-server) 配置示例

bootstrap.yml 配置详解:

server:
  port: 8666 # 网关服务端口,所有外部请求的统一入口

spring:
  application:
    name: gateway-server # 网关服务名称
  main:
    web-application-type: reactive # 强制声明为响应式Web环境(Gateway要求)
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848 # Nacos配置中心地址
        namespace: public # 与其他服务保持一致的命名空间
        shared-configs:
          - data-id: nacos-discovery.yaml # 服务发现配置
            group: DEFAULT_GROUP
            refresh: false
    gateway:
      discovery:
        locator:
          enabled: true # 启用服务发现路由,自动为注册的服务创建路由
          lower-case-service-id: true # 服务ID转换为小写,避免大小写问题

1.5 使用流程

  1. 启动 Nacos Server (默认端口 8848)
  2. 配置服务信息 在 bootstrap.yml 中配置服务名和 Nacos 地址
  3. 添加注解 在启动类上添加 @EnableDiscoveryClient
  4. 启动服务 服务自动注册到 Nacos
  5. 访问 Nacos 控制台 查看注册的服务实例

1.6 Nacos 工作流程图

sequenceDiagram
    participant App as 微服务应用
    participant Nacos as Nacos Server
    participant Client as 客户端调用

    App->>Nacos: 1. 服务注册
    Nacos->>App: 2. 注册成功响应
    App->>Nacos: 3. 发送心跳保活
    Client->>Nacos: 4. 服务发现请求
    Nacos->>Client: 5. 返回服务实例列表
    Client->>App: 6. 负载均衡调用服务
    App->>Client: 7. 返回业务结果

    Note over App,Nacos: 配置热更新
    Nacos->>App: 8. 推送配置变更
    App->>App: 9. 动态刷新配置

2. OpenFeign 服务间调用

OpenFeign 负载均衡

2.1 作用

  • 声明式 HTTP 客户端: 简化服务间的 HTTP 调用
  • 负载均衡: 内置 Ribbon 负载均衡功能
  • 熔断降级: 结合 Sentinel 提供熔断功能

2.2 Maven 依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

2.3 实际项目中的核心注解配置

启动类配置 (product-server 示例):

@SpringBootApplication                                              // Spring Boot主启动类注解
@EnableDiscoveryClient                                             // 启用服务发现客户端功能
@MapperScan("com.example.productserver.mapper")                   // 扫描MyBatis Mapper接口包
@EnableFeignClients(basePackages = "com.example.productserver.client") // 扫描Feign客户端接口包
public class ProductServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductServerApplication.class, args);
    }
}

Feign 客户端接口 (实际项目代码):

/**
 * 调用用户服务的Feign客户端
 * name: 目标服务在Nacos中注册的服务名
 * contextId: 唯一标识,避免多个Feign接口冲突
 * fallback: 熔断降级处理类
 */
@FeignClient(
    name = "user-server",                                          // 目标服务名(对应bootstrap.yml中的spring.application.name)
    contextId = "ShopUserServiceFeignByProduct",                   // 上下文ID,区分不同的Feign客户端
    fallback = ShopUserServiceFeignFallback.class                 // 熔断回调类,服务异常时调用
)
public interface ShopUserServiceFeign {

    /**
     * 根据用户ID获取用户信息
     * 映射到user-server服务的/api/shopUser/user/{id}接口
     */
    @GetMapping("/api/shopUser/user/{id}")
    ShopUser getUserById(@PathVariable("id") Integer id);
}

2.4 熔断回调类

@Component("ShopUserServiceFeignFallback")
@Slf4j
public class ShopUserServiceFeignFallback implements ShopUserServiceFeign {

    @Override
    public ShopUser getUserById(Integer id) {
        log.error("调用 user-server 失败,触发熔断,id: {}", id);
        return new ShopUser();  // 返回默认值
    }
}

2.5 使用流程

  1. 添加依赖 在 pom.xml 中添加 OpenFeign 依赖
  2. 启用 Feign 在启动类添加 @EnableFeignClients 注解
  3. 定义接口 创建 Feign 客户端接口,使用 @FeignClient 注解
  4. 实现熔断 创建熔断回调类实现接口
  5. 注入使用 在需要的地方注入 Feign 接口并调用

2.6 OpenFeign 调用流程图

graph LR
    A[Controller] -->|注入| B[Feign接口]
    B -->|动态代理| C[Feign代理对象]
    C -->|服务发现| D[Nacos注册中心]
    D -->|返回实例列表| C
    C -->|负载均衡| E[Ribbon/LoadBalancer]
    E -->|选择实例| F[目标服务实例]
    F -->|HTTP调用| G[目标服务]
    G -->|返回结果| F
    F -->|响应| E
    E -->|结果| C
    C -->|反序列化| B
    B -->|返回对象| A

    style A fill:#e3f2fd
    style B fill:#f3e5f5
    style C fill:#e8f5e8
    style D fill:#fff3e0
    style E fill:#fce4ec
    style F fill:#f1f8e9
    style G fill:#ffebee

3. Spring Cloud Gateway 网关

Gateway 路由

3.1 作用

  • 统一入口: 所有外部请求的统一入口
  • 路由转发: 根据规则将请求转发到对应的微服务
  • 过滤器: 提供请求前后处理能力

3.2 Maven 依赖

<!-- 网关核心依赖 -->
<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>

3.3 核心注解

@SpringBootApplication
@EnableDiscoveryClient  // 启用服务发现
public class GatewayServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayServerApplication.class, args);
    }
}

3.4 配置文件

server:
  port: 8666
spring:
  application:
    name: gateway-server
  main:
    web-application-type: reactive # 声明为响应式环境
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        namespace: public
    gateway:
      discovery:
        locator:
          enabled: true # 启用服务发现路由
          lower-case-service-id: true # 服务名小写

3.5 使用流程

  1. 创建网关模块 单独的 gateway-server 模块
  2. 添加依赖 gateway 和 nacos-discovery 依赖
  3. 配置路由 在配置文件中配置路由规则
  4. 启动网关 网关自动从 Nacos 发现服务并生成路由
  5. 访问测试 通过网关地址访问后端服务

3.6 Gateway 路由流程图

graph TD
    A[客户端请求] -->|http://gateway:8666| B[Gateway网关]
    B -->|路由匹配| C{路由谓词判断}
    C -->|/user/**| D[用户服务路由]
    C -->|/product/**| E[商品服务路由]
    C -->|/order/**| F[订单服务路由]
    D -->|负载均衡| G[user-server实例]
    E -->|负载均衡| H[product-server实例]
    F -->|负载均衡| I[order-server实例]
    G -->|业务处理| J[用户业务逻辑]
    H -->|业务处理| K[商品业务逻辑]
    I -->|业务处理| L[订单业务逻辑]
    J -->|响应| G
    K -->|响应| H
    L -->|响应| I
    G -->|返回结果| D
    H -->|返回结果| E
    I -->|返回结果| F
    D -->|统一响应| B
    E -->|统一响应| B
    F -->|统一响应| B
    B -->|最终响应| A

    style A fill:#e3f2fd
    style B fill:#f3e5f5
    style C fill:#fff3e0
    style D fill:#e8f5e8
    style E fill:#e8f5e8
    style F fill:#e8f5e8

4. Ribbon/LoadBalancer 负载均衡

Ribbon LoadBalancer

4.1 作用

  • 客户端负载均衡: 在客户端实现负载均衡算法
  • 多种策略: 支持轮询、随机、权重等多种负载均衡策略
  • 服务发现集成: 与 Nacos 等注册中心无缝集成
  • 健康检查: 自动剔除不健康的服务实例

4.2 技术演进说明

在 Spring Cloud 生态中,负载均衡经历了以下演进:

  • Spring Cloud 2020.0.0 之前: 使用 Netflix Ribbon
  • Spring Cloud 2020.0.0 之后: 使用 Spring Cloud LoadBalancer 替代 Ribbon

本项目使用的是 Hoxton.SR9 版本,因此主要使用 Ribbon 作为负载均衡组件。

4.3 Maven 依赖

<!-- Ribbon 通过 OpenFeign 自动引入,无需单独添加 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

<!-- 如果需要单独使用 Ribbon -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

<!-- Spring Cloud LoadBalancer (新版本) -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

4.4 核心注解和配置

// 1. 使用 @LoadBalanced 注解
@Configuration
public class RestTemplateConfig {

    @Bean
    @LoadBalanced  // 启用负载均衡
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

// 2. 自定义负载均衡策略
@Configuration
public class RibbonConfig {

    @Bean
    public IRule ribbonRule() {
        // 随机策略
        return new RandomRule();

        // 其他可选策略:
        // return new RoundRobinRule();     // 轮询(默认)
        // return new WeightedResponseTimeRule(); // 权重响应时间
        // return new BestAvailableRule();  // 最少并发
        // return new RetryRule();          // 重试
    }
}

// 3. 针对特定服务配置负载均衡
@RibbonClient(name = "user-server", configuration = UserServiceRibbonConfig.class)
@Configuration
public class RibbonConfiguration {
}

// 4. RestTemplate 使用示例
@Service
public class ProductService {

    @Autowired
    private RestTemplate restTemplate;

    public ShopUser getUserById(Integer id) {
        // 直接使用服务名,Ribbon 自动负载均衡
        String url = "http://user-server/api/shopUser/user/" + id;
        return restTemplate.getForObject(url, ShopUser.class);
    }
}

4.5 配置文件设置

# Ribbon 全局配置
ribbon:
  ConnectTimeout: 3000 # 连接超时时间
  ReadTimeout: 60000 # 读取超时时间
  MaxAutoRetries: 1 # 对当前实例的重试次数
  MaxAutoRetriesNextServer: 1 # 切换实例的重试次数
  OkToRetryOnAllOperations: false # 是否对所有操作重试

# 针对特定服务的配置
user-server:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 随机策略
    ConnectTimeout: 3000
    ReadTimeout: 10000

product-server:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule # 轮询策略

4.6 负载均衡策略详解

graph TD
    A[负载均衡策略] --> B[RoundRobinRule<br/>轮询策略<br/>⭐默认]
    A --> C[RandomRule<br/>随机策略<br/>🎲随机选择]
    A --> D[WeightedResponseTimeRule<br/>权重响应时间<br/>⚡性能优先]
    A --> E[BestAvailableRule<br/>最少并发策略<br/>🚦并发控制]
    A --> F[RetryRule<br/>重试策略<br/>🔄容错机制]
    A --> G[AvailabilityFilteringRule<br/>可用过滤策略<br/>🛡️健康检查]
    A --> H[ZoneAvoidanceRule<br/>区域权衡策略<br/>🌍区域感知]

    style A fill:#e3f2fd
    style B fill:#e8f5e8
    style C fill:#fff3e0
    style D fill:#f3e5f5
    style E fill:#fce4ec
    style F fill:#f1f8e9
    style G fill:#ffebee
    style H fill:#e0f2f1
策略类 策略名称 描述 使用场景
RoundRobinRule 轮询策略 默认策略,按顺序依次选择服务实例 🔄 均匀分布
RandomRule 随机策略 随机选择一个可用的服务实例 🎲 简单场景
WeightedResponseTimeRule 权重响应时间 根据响应时间分配权重,响应时间越短权重越高 ⚡ 性能敏感
BestAvailableRule 最少并发策略 选择并发请求数最少的服务实例 🚦 高并发
RetryRule 重试策略 在指定时间内重试获取可用实例 🔄 高可用
AvailabilityFilteringRule 可用过滤策略 过滤掉故障实例和并发超过阈值的实例 🛡️ 稳定性
ZoneAvoidanceRule 区域权衡策略 综合判断区域性能和可用性选择实例 🌍 多机房

4.7 项目中的实际使用

在本项目中,负载均衡主要通过 OpenFeign 自动实现:

// Feign 客户端自动集成 Ribbon 负载均衡
@FeignClient(name = "user-server", contextId = "ShopUserServiceFeignByProduct")
public interface ShopUserServiceFeign {

    @GetMapping("/api/shopUser/user/{id}")
    ShopUser getUserById(@PathVariable("id") Integer id);
}

// 在 Controller 中使用
@RestController
public class ProductController {

    @Resource
    private ShopUserServiceFeign userServiceFeign;

    @GetMapping("/product/user/{id}")
    public BaseResult<ShopUser> getProductWithUser(@PathVariable Integer id) {
        // Feign 自动进行负载均衡调用
        ShopUser user = userServiceFeign.getUserById(id);
        return BaseResult.success(user);
    }
}

4.8 测试负载均衡

  1. 启动多个相同服务实例:

    # 启动多个 user-server 实例
    java -jar user-server.jar --server.port=8444
    java -jar user-server.jar --server.port=8445
    java -jar user-server.jar --server.port=8446
    
  2. 观察负载均衡效果:

    • 多次调用同一个接口
    • 查看日志中的端口号变化
    • 验证请求是否均匀分布到各个实例
  3. 监控和统计:

    @RestController
    public class ProductController {
    
        @Value("${server.port}")
        private String serverPort;
    
        @GetMapping("/product/user/{id}")
        public BaseResult<ShopUser> getProductWithUser(@PathVariable Integer id) {
            log.info("当前处理请求的服务端口: {}", serverPort);
            ShopUser user = userServiceFeign.getUserById(id);
            return BaseResult.success(user);
        }
    }
    

4.9 使用流程

  1. 自动集成: OpenFeign 自动集成 Ribbon,无需额外配置
  2. 启动多实例: 启动同一服务的多个实例
  3. 服务注册: 多个实例自动注册到 Nacos
  4. 自动负载均衡: Feign 调用时自动在多个实例间负载均衡
  5. 策略调优: 根据需要调整负载均衡策略和参数

4.10 Spring Cloud LoadBalancer (新版本)

如果升级到新版本 Spring Cloud,可以使用 LoadBalancer 替代 Ribbon:

// LoadBalancer 配置
@Configuration
public class LoadBalancerConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    // 自定义负载均衡策略
    @Bean
    public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(loadBalancerClientFactory
                .getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }
}

5. Sentinel 熔断限流

Sentinel 保护

5.1 作用

  • 流量控制: 限制访问流量,防止系统过载
  • 熔断降级: 服务异常时快速失败,防止级联故障
  • 系统保护: 系统负载过高时自动降级

5.2 Maven 依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

5.3 核心注解

@SentinelResource(
    value = "getUserById",           // 资源名称
    fallback = "getUserByIdFallback", // 降级方法
    blockHandler = "getUserByIdBlockHandler" // 限流方法
)
public ShopUser getUserById(Integer id) {
    // 业务逻辑
}

// 降级方法
public ShopUser getUserByIdFallback(Integer id, Throwable ex) {
    log.error("获取用户信息降级,id: {}, 异常: {}", id, ex.getMessage());
    return new ShopUser();
}

// 限流方法
public ShopUser getUserByIdBlockHandler(Integer id, BlockException ex) {
    log.warn("获取用户信息被限流,id: {}", id);
    return new ShopUser();
}

5.4 实际项目中的 Sentinel 配置详解

在 user-server 的 application.yml 中配置

spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080 # Sentinel Dashboard控制台地址
        # Dashboard用于查看实时监控数据、配置流控规则等
        port: 8719 # 客户端与Dashboard通信的端口
        # 如果端口被占用,会自动尝试8719+1, 8719+2...直到找到可用端口
      eager:
        true # 服务启动时立即连接Dashboard
        # 默认false,即首次访问时才建立连接;true则启动时就连接

# Feign 与 Sentinel 集成配置
feign:
  sentinel:
    enabled: true # 开启Feign的Sentinel熔断支持
    # 开启后,所有@FeignClient都会自动支持熔断降级

在 Nacos 配置中心的 sentinel-public.yaml 配置

spring:
  cloud:
    sentinel:
      # 流控规则配置(也可在Dashboard界面配置)
      flow:
        - resource: getUserById # 资源名称(对应@SentinelResource的value)
          grade: 1 # 流控模式:0-线程数 1-QPS
          count: 10 # 流控阈值:每秒最多10个请求
          strategy: 0 # 流控策略:0-直接 1-关联 2-链路
          controlBehavior: 0 # 流控效果:0-快速失败 1-Warm Up 2-排队等待
      # 熔断规则配置
      degrade:
        - resource: getUserById # 资源名称
          grade: 2 # 熔断策略:0-RT 1-异常比例 2-异常数
          count: 5 # 异常数阈值:5个异常后熔断
          timeWindow: 10 # 熔断时长:10秒后恢复
          minRequestAmount: 5 # 最小请求数:至少5个请求才触发统计
      # 系统保护规则
      system:
        - highestSystemLoad: 8.0 # 系统最高负载
          avgRt: 1000 # 平均响应时间(ms)
          maxThread: 100 # 最大线程数
          qps: 1000 # 系统QPS阈值

配置项详细说明

配置项 说明 可选值 作用
dashboard Dashboard 地址 IP:端口 连接监控控制台
port 通信端口 8719-8729 与 Dashboard 数据传输
eager 是否立即连接 true/false 控制连接时机
grade 流控模式 0=线程数,1=QPS 流控依据
count 流控阈值 数值 触发流控的临界值
strategy 流控策略 0=直接,1=关联,2=链路 流控触发方式
controlBehavior 流控效果 0=快速失败,1=预热,2=排队 流控后的处理方式

5.5 使用流程

  1. 添加依赖 在需要保护的服务中添加 sentinel 依赖
  2. 配置连接 配置 Sentinel Dashboard 连接信息
  3. 添加注解 在需要保护的方法上添加 @SentinelResource
  4. 实现降级 编写降级和限流处理方法
  5. 启动控制台 启动 Sentinel Dashboard 进行规则配置

5.6 Sentinel 保护机制图

graph TD
    A[客户端请求] --> B{Sentinel控制台}
    B -->|通过检查| C[业务逻辑处理]
    B -->|触发限流| D[限流处理]
    B -->|触发熔断| E[熔断处理]
    B -->|系统保护| F[系统保护处理]

    C --> G[正常业务响应]
    D --> H[限流响应<br/>BlockException]
    E --> I[熔断降级响应<br/>Fallback方法]
    F --> J[系统保护响应<br/>拒绝请求]

    G --> K[返回结果]
    H --> K
    I --> K
    J --> K

    L[Sentinel Dashboard] -->|配置规则| B
    B -->|实时监控| L

    style A fill:#e3f2fd
    style B fill:#ffebee
    style C fill:#e8f5e8
    style D fill:#fff3e0
    style E fill:#f3e5f5
    style F fill:#fce4ec
    style L fill:#f1f8e9

6. Seata 分布式事务

Seata ACID

6.1 作用

  • 分布式事务: 保证跨服务的数据一致性
  • 事务协调: AT、TCC、SAGA 多种事务模式
  • 性能优化: 高性能的分布式事务解决方案

6.2 Maven 依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

6.3 核心注解

@GlobalTransactional(rollbackFor = Exception.class)
public BaseResult decreaseStockAndIncreaseIntegral(Long orderId) {
    // 1. 校验订单
    ShopOrder order = shopOrderService.getById(orderId);

    // 2. 扣减库存 (调用 product-server)
    BaseResult result = shopProductServiceFeign.decreaseStock(order);

    // 3. 增加积分 (调用 user-server)
    shopUserServiceFeign.increaseIntegral(order);

    return BaseResult.success("业务处理成功");
}

6.4 使用流程

  1. 启动 Seata Server 部署 Seata TC (事务协调器)
  2. 添加依赖 在参与分布式事务的服务中添加依赖
  3. 配置连接 配置 Seata Server 连接信息
  4. 添加注解 在事务发起方法上添加 @GlobalTransactional
  5. 数据库配置 为每个数据库添加 undo_log 表

6.5 Seata 分布式事务流程图

sequenceDiagram
    participant Order as 订单服务
    participant TC as Seata TC
    participant Product as 商品服务
    participant User as 用户服务
    participant DB1 as 订单数据库
    participant DB2 as 商品数据库
    participant DB3 as 用户数据库

    Order->>TC: 1. 开启全局事务
    TC->>Order: 2. 返回全局事务ID

    Order->>Product: 3. 扣减库存(携带XID)
    Product->>DB2: 4. 执行SQL+记录undo_log
    DB2->>Product: 5. 执行成功
    Product->>TC: 6. 注册分支事务
    Product->>Order: 7. 返回成功

    Order->>User: 8. 增加积分(携带XID)
    User->>DB3: 9. 执行SQL+记录undo_log
    DB3->>User: 10. 执行成功
    User->>TC: 11. 注册分支事务
    User->>Order: 12. 返回成功

    Order->>DB1: 13. 创建订单+记录undo_log
    DB1->>Order: 14. 执行成功

    Order->>TC: 15. 提交全局事务
    TC->>Product: 16. 提交分支事务
    TC->>User: 17. 提交分支事务
    TC->>Order: 18. 全局事务提交成功

    Note over Order,DB3: 如果任一步骤失败,TC会协调所有参与者回滚

7. MyBatis-Plus ORM 框架

MyBatis-Plus 数据库

7.1 作用

  • ORM 映射: 对象关系映射,简化数据库操作
  • 代码生成: 自动生成 Mapper、Service 等代码
  • 增强功能: 分页、条件构造器等增强功能

7.2 Maven 依赖

<!-- MyBatis-Plus 核心依赖 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.2</version>
</dependency>

<!-- MySQL 8.0 驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.23</version>
    <scope>runtime</scope>
</dependency>

7.3 实际项目中的核心注解和配置

启动类配置 (user-server 示例):

@SpringBootApplication                                              // Spring Boot主启动类
@EnableDiscoveryClient                                             // 启用Nacos服务发现功能
@MapperScan("com.example.userserver.mapper")                      // 扫描MyBatis Mapper接口包
public class UserServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServerApplication.class, args);
    }
}

实体类配置 (实际项目 ShopUser):

/**
 * 用户表实体类
 * @TableName 指定对应的数据库表名
 */
@TableName(value = "shop_user")                                    // 指定数据库表名
@Data                                                              // Lombok注解,生成getter/setter等方法
public class ShopUser implements Serializable {

    /**
     * 主键字段
     * @TableId 指定主键策略
     */
    @TableId(type = IdType.AUTO)                                   // 主键自增策略
    private Integer id;

    /**
     * 用户账号
     */
    private String username;                                        // 字段名与数据库列名相同,无需@TableField

    /**
     * 用户密码
     */
    private String userpass;

    /**
     * 真实姓名
     */
    private String truename;

    /**
     * 用户积分
     */
    private Integer score;

    @TableField(exist = false)                                     // 标识非数据库字段
    private static final long serialVersionUID = 1L;
}

Mapper 接口 (实际项目配置):

/**
 * 用户数据访问层接口
 * 继承BaseMapper获得基础CRUD操作
 */
@Mapper                                                            // MyBatis Mapper标识注解
public interface ShopUserMapper extends BaseMapper<ShopUser> {
    // 继承BaseMapper后自动拥有以下方法:
    // - insert(entity): 插入记录
    // - deleteById(id): 根据ID删除
    // - updateById(entity): 根据ID更新
    // - selectById(id): 根据ID查询
    // - selectList(wrapper): 条件查询
    // 等基础CRUD方法,无需手动实现
}

Service 实现类 (业务逻辑层):

@Service                                                           // Spring服务层注解
public class ShopUserServiceImpl extends ServiceImpl<ShopUserMapper, ShopUser>
        implements ShopUserService {

    /**
     * 增加用户积分的业务方法
     * 使用MyBatis-Plus的条件构造器进行更新操作
     */
    public void increaseIntegral(ShopOrder shopOrder) {
        // 创建Lambda更新条件构造器,类型安全
        LambdaUpdateWrapper<ShopUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper
                .setSql("score = score + " + shopOrder.getPoints())        // 设置SQL片段,积分增加
                .eq(ShopUser::getId, shopOrder.getUserId());               // 条件:用户ID等于订单用户ID

        boolean updateSuccess = update(updateWrapper);                     // 执行更新操作
        if (!updateSuccess) {
            throw new RuntimeException("增加积分失败");                    // 更新失败抛异常
        }
    }
}

7.4 实际项目数据库配置详解

在 Nacos 配置中心的 mysql-shopuser.yaml 配置 (通过 shared-configs 引入):

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver # MySQL 8.0+ 驱动类
    url: jdbc:mysql://localhost:3306/shop_user?useSSL=false&serverTimezone=Asia/Shanghai
    # 数据库连接URL详解:
    # - localhost:3306: MySQL服务器地址和端口
    # - shop_user: 数据库名称,各服务独立数据库
    # - useSSL=false: 关闭SSL连接(开发环境)
    # - serverTimezone=Asia/Shanghai: 设置时区为上海
    username: root # 数据库用户名
    password: 123456 # 数据库密码(生产环境需加密)

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true # 开启下划线转驼峰命名
    # 数据库字段shop_name -> Java属性shopName
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台打印SQL日志(开发调试用)
    # 生产环境建议关闭或使用其他日志实现
  global-config:
    db-config:
      id-type: auto # 主键策略:数据库自增
      # AUTO: 数据库ID自增
      # ASSIGN_ID: 雪花算法生成ID
      # ASSIGN_UUID: UUID生成
      logic-delete-field: deleted # 逻辑删除字段名
      logic-delete-value: 1 # 逻辑删除值(删除)
      logic-not-delete-value: 0 # 逻辑删除值(未删除)
      # 逻辑删除:不实际删除数据,只标记deleted字段
  mapper-locations: classpath*:/mapper/**/*.xml # Mapper XML文件位置
  type-aliases-package: com.example.commonserver.model.vo # 实体类包名,简化XML中的类型引用

Maven 依赖配置详解

<!-- MyBatis-Plus 核心依赖 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.2</version>                    <!-- 兼容Spring Boot 2.3.x的稳定版本 -->
</dependency>

<!-- MySQL 8.0 驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.23</version>                   <!-- 支持JDK 1.8的MySQL 8.0驱动 -->
    <scope>runtime</scope>                      <!-- 运行时依赖,编译时不需要 -->
</dependency>

7.5 使用流程

  1. 添加依赖 MyBatis-Plus 和数据库驱动依赖
  2. 配置数据源 在配置文件中配置数据库连接
  3. 扫描 Mapper 在启动类添加 @MapperScan 注解
  4. 创建实体 使用注解配置实体类和表的映射
  5. 继承接口 Mapper 继承 BaseMapper,Service 继承 ServiceImpl

8. RabbitMQ 消息队列

RabbitMQ 异步通信

8.1 作用

  • 异步通信: 实现服务间的异步消息传递
  • 削峰填谷: 处理高并发请求,平衡系统负载
  • 解耦服务: 降低服务间的直接依赖关系
  • 可靠传输: 保证消息的可靠投递和消费

8.2 Maven 依赖

<!-- RabbitMQ 依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

<!-- RabbitMQ 测试依赖 -->
<dependency>
    <groupId>org.springframework.amqp</groupId>
    <artifactId>spring-rabbit-test</artifactId>
    <scope>test</scope>
</dependency>

8.3 核心注解

// 启动类配置
@EnableRabbit  // 启用 RabbitMQ 支持

// 消息生产者
@Component
public class OrderProducer {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendOrderMessage(OrderMessage message) {
        rabbitTemplate.convertAndSend("order.exchange", "order.create", message);
    }
}

// 消息消费者
@Component
public class OrderConsumer {
    @RabbitListener(queues = "order.queue")
    public void handleOrderMessage(@Payload OrderMessage message) {
        // 处理订单消息
        log.info("接收到订单消息: {}", message);
    }
}

// 队列配置
@Configuration
public class RabbitConfig {

    @Bean
    public TopicExchange orderExchange() {
        return new TopicExchange("order.exchange");
    }

    @Bean
    public Queue orderQueue() {
        return QueueBuilder.durable("order.queue").build();
    }

    @Bean
    public Binding orderBinding() {
        return BindingBuilder.bind(orderQueue())
                .to(orderExchange())
                .with("order.*");
    }
}

8.4 配置文件

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: admin
    password: admin
    virtual-host: /
    # 连接池配置
    connection-timeout: 15000
    # 发布确认
    publisher-confirm-type: correlated
    publisher-returns: true
    # 消费者配置
    listener:
      simple:
        acknowledge-mode: manual
        retry:
          enabled: true
          max-attempts: 3
          initial-interval: 1000

8.5 使用流程

  1. 安装 RabbitMQ 启动 RabbitMQ 服务器
  2. 添加依赖 在 pom.xml 中添加 RabbitMQ 依赖
  3. 配置连接 在 application.yml 中配置连接信息
  4. 定义队列 创建交换机、队列和绑定关系
  5. 发送消息 使用 RabbitTemplate 发送消息
  6. 消费消息 使用 @RabbitListener 注解消费消息

8.6 RabbitMQ 消息流转图

graph TD
    A[生产者服务] -->|发送消息| B[Exchange交换机]
    B -->|路由规则| C{路由判断}
    C -->|order.create| D[订单队列]
    C -->|order.update| E[订单更新队列]
    C -->|order.cancel| F[订单取消队列]

    D -->|消费消息| G[订单处理服务]
    E -->|消费消息| H[订单更新服务]
    F -->|消费消息| I[订单取消服务]

    G -->|处理完成| J[业务逻辑]
    H -->|处理完成| K[更新库存]
    I -->|处理完成| L[退款处理]

    style A fill:#e3f2fd
    style B fill:#f3e5f5
    style C fill:#fff3e0
    style D fill:#e8f5e8
    style E fill:#e8f5e8
    style F fill:#e8f5e8
    style G fill:#ffebee
    style H fill:#ffebee
    style I fill:#ffebee

9. RocketMQ 消息队列

RocketMQ 高性能

9.1 作用

  • 高吞吐量: 单机支持万级别的消息处理
  • 分布式事务: 支持分布式事务消息
  • 顺序消息: 保证消息的严格顺序消费
  • 延时消息: 支持定时和延时消息投递

9.2 Maven 依赖

<!-- RocketMQ Spring Boot Starter -->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>

<!-- RocketMQ 客户端 -->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-client</artifactId>
    <version>4.9.4</version>
</dependency>

9.3 核心注解

// 消息生产者
@Component
public class PaymentProducer {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    // 普通消息
    public void sendPaymentMessage(PaymentMessage message) {
        rocketMQTemplate.convertAndSend("payment-topic", message);
    }

    // 延时消息
    public void sendDelayMessage(PaymentMessage message) {
        rocketMQTemplate.syncSend("payment-topic",
            MessageBuilder.withPayload(message).build(),
            3000, // 超时时间
            3     // 延时等级 3 = 10秒
        );
    }

    // 事务消息
    @Transactional
    public void sendTransactionMessage(PaymentMessage message) {
        rocketMQTemplate.sendMessageInTransaction("payment-topic",
            MessageBuilder.withPayload(message).build(), null);
    }
}

// 消息消费者
@Component
@RocketMQMessageListener(
    topic = "payment-topic",
    consumerGroup = "payment-consumer-group",
    messageModel = MessageModel.CLUSTERING
)
public class PaymentConsumer implements RocketMQListener<PaymentMessage> {

    @Override
    public void onMessage(PaymentMessage message) {
        log.info("接收到支付消息: {}", message);
        // 处理支付逻辑
        processPayment(message);
    }

    private void processPayment(PaymentMessage message) {
        // 支付处理逻辑
    }
}

// 事务监听器
@RocketMQTransactionListener
public class PaymentTransactionListener implements RocketMQLocalTransactionListener {

    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        // 执行本地事务
        try {
            // 业务逻辑处理
            return RocketMQLocalTransactionState.COMMIT;
        } catch (Exception e) {
            return RocketMQLocalTransactionState.ROLLBACK;
        }
    }

    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
        // 检查本地事务状态
        return RocketMQLocalTransactionState.COMMIT;
    }
}

9.4 配置文件

rocketmq:
  name-server: localhost:9876
  producer:
    group: payment-producer-group
    send-message-timeout: 300000
    compress-message-body-threshold: 4096
    max-message-size: 4194304
    retry-times-when-send-async-failed: 2
    retry-next-server: true
    retry-times-when-send-failed: 2
  consumer:
    group: payment-consumer-group
    consume-thread-min: 5
    consume-thread-max: 32
    consume-message-batch-max-size: 1

9.5 使用流程

  1. 启动 NameServer 启动 RocketMQ NameServer
  2. 启动 Broker 启动 RocketMQ Broker 服务
  3. 添加依赖 在项目中添加 RocketMQ 依赖
  4. 配置连接 配置 NameServer 地址
  5. 发送消息 使用 RocketMQTemplate 发送消息
  6. 消费消息 使用 @RocketMQMessageListener 消费消息

9.6 RocketMQ 分布式事务消息流程图

sequenceDiagram
    participant App as 应用服务
    participant Producer as 生产者
    participant Broker as RocketMQ Broker
    participant Consumer as 消费者
    participant DB as 数据库

    App->>Producer: 1. 发送事务消息
    Producer->>Broker: 2. 发送Half消息
    Broker->>Producer: 3. Half消息发送成功

    Producer->>DB: 4. 执行本地事务
    DB->>Producer: 5. 本地事务结果

    alt 本地事务成功
        Producer->>Broker: 6a. 提交事务(Commit)
        Broker->>Consumer: 7a. 投递消息给消费者
        Consumer->>Consumer: 8a. 消费消息
    else 本地事务失败
        Producer->>Broker: 6b. 回滚事务(Rollback)
        Note over Broker: Half消息被删除
    end

    Note over Broker,Producer: 如果长时间未收到确认
    Broker->>Producer: 9. 回查本地事务状态
    Producer->>Broker: 10. 返回事务状态

10. 消息队列对比分析

10.1 RabbitMQ vs RocketMQ 特性对比

特性 RabbitMQ RocketMQ 推荐场景
性能 万级/秒 十万级/秒 RocketMQ 适合高并发
可靠性 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 两者都很可靠
功能丰富度 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ RabbitMQ 功能更丰富
运维复杂度 ⭐⭐⭐ ⭐⭐⭐⭐ RabbitMQ 相对简单
分布式事务 RocketMQ 支持
延时消息 需插件 ✅ 原生支持 RocketMQ 更便捷
顺序消息 两者都支持
社区生态 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ RabbitMQ 生态更成熟

11. 中间件集成架构图

🎨 完整架构拓扑图

graph TB
    subgraph "客户端层"
        A[Web浏览器]
        B[移动应用]
        C[其他系统]
    end

    subgraph "网关层"
        D[Spring Cloud Gateway<br/>:8666]
    end

    subgraph "服务层"
        E[用户服务<br/>user-server:8444]
        F[商品服务<br/>product-server:8333]
        G[订单服务<br/>order-server:8222]
        H[公共服务<br/>common-server:8111]
    end

    subgraph "注册发现层"
        I[Nacos Server<br/>:8848<br/>服务注册&配置中心]
    end

    subgraph "监控保护层"
        J[Sentinel Dashboard<br/>:8080<br/>流量控制&熔断]
        K[Seata Server<br/>分布式事务协调]
    end

    subgraph "消息中间件层"
        M[RabbitMQ<br/>:5672<br/>消息队列]
        N[RocketMQ<br/>:9876<br/>分布式消息]
    end

    subgraph "数据层"
        O[MySQL数据库<br/>业务数据存储]
        P[Redis缓存<br/>缓存加速]
    end

    %% 连接关系
    A --> D
    B --> D
    C --> D

    D -->|路由转发| E
    D -->|路由转发| F
    D -->|路由转发| G

    E -.->|OpenFeign调用| F
    E -.->|OpenFeign调用| G
    F -.->|OpenFeign调用| E
    F -.->|OpenFeign调用| G
    G -.->|OpenFeign调用| E
    G -.->|OpenFeign调用| F

    E -->|服务注册| I
    F -->|服务注册| I
    G -->|服务注册| I
    D -->|服务发现| I

    E -->|流量监控| J
    F -->|流量监控| J
    G -->|流量监控| J

    E -->|分布式事务| K
    F -->|分布式事务| K
    G -->|分布式事务| K

    E -->|异步消息| M
    F -->|异步消息| M
    G -->|异步消息| M

    E -->|分布式消息| N
    F -->|分布式消息| N
    G -->|分布式消息| N

    E -->|数据访问| O
    F -->|数据访问| O
    G -->|数据访问| O

    E -.->|缓存访问| P
    F -.->|缓存访问| P
    G -.->|缓存访问| P

    %% 样式定义
    style A fill:#e3f2fd
    style B fill:#e3f2fd
    style C fill:#e3f2fd
    style D fill:#f3e5f5
    style E fill:#e8f5e8
    style F fill:#e8f5e8
    style G fill:#e8f5e8
    style H fill:#e8f5e8
    style I fill:#fff3e0
    style J fill:#ffebee
    style K fill:#f1f8e9
    style M fill:#ffe0e6
    style N fill:#ffebe6
    style O fill:#fce4ec
    style P fill:#e0f2f1

📊 中间件技术栈总览

mindmap
  root((Spring Cloud<br/>微服务生态))
    注册发现
      Nacos
        服务注册
        服务发现
        配置中心
        健康检查
    服务调用
      OpenFeign
        声明式调用
        负载均衡
        熔断降级
        超时重试
    网关路由
      Gateway
        统一入口
        路由转发
        过滤器链
        限流鉴权
    负载均衡
      Ribbon
        客户端LB
        多种策略
        健康检查
        故障转移
    保护机制
      Sentinel
        流量控制
        熔断降级
        系统保护
        热点防护
    分布式事务
      Seata
        AT模式
        TCC模式
        SAGA模式
        XA模式
    消息队列
      RabbitMQ
        异步通信
        削峰填谷
        发布订阅
        路由灵活
      RocketMQ
        高吞吐量
        分布式事务
        延时消息
        顺序消息

12. 总结

总结 架构

🏆 实际使用的核心中间件能力矩阵

中间件 项目中的实际应用 解决的实际问题 配置复杂度 项目收益
Nacos 服务注册发现和配置中心 服务发现、配置集中管理 ⭐⭐⭐ 🔥🔥🔥🔥🔥
OpenFeign 跨服务调用(product 调 user) 服务间通信简化 ⭐⭐ 🔥🔥🔥🔥🔥
Gateway 统一网关入口(8666 端口) 请求路由转发 ⭐⭐⭐ 🔥🔥🔥🔥🔥
Ribbon 内置于 OpenFeign 的负载均衡 product-server 集群 🔥🔥🔥🔥
Sentinel 流量控制和熔断保护 服务稳定性保障 ⭐⭐⭐⭐ 🔥🔥🔥🔥🔥
Seata 分布式事务协调 订单-库存-积分一致性 ⭐⭐⭐⭐⭐ 🔥🔥🔥🔥

注意: 项目中移除了 RabbitMQ 和 RocketMQ 相关内容,专注于服务治理和数据一致性。

#微服务#
全部评论

相关推荐

不愿透露姓名的神秘牛友
06-21 11:29
牛客330674826号:你是孝子吗,这么喜欢当引流狗
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务