Spring Cloud Alibaba微服务开发最佳实践:
- Spring Cloud Gateway:网关
- Nacos:服务注册和配置中心
- Sentinel:熔断限流
- Seata:分布式事务
- RocketMQ/RabbitMQ/Kafka:消息队列,削峰填谷

一、Spring boot、Spring Cloud、Spring Cloud Alibaba 三者有严格的兼容关系,版本必须匹配:
xml
<properties>
<!-- 指定 JDK 版本为 17,这是 Spring Boot 3.x 的硬性要求 [citation:3][citation:7] -->
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 与 Spring Boot 3.2.12 兼容 -->
<jackson.version>2.15.3</jackson.version>
<!-- 核心框架版本 - 三者版本必须严格兼容 -->
<!-- Spring Boot 3.2.x 是推荐版本 [citation:1][citation:9] -->
<spring.boot.version>3.2.12</spring.boot.version>
<!-- Spring Cloud 2023.0.x 系列 [citation:1][citation:9] -->
<spring.cloud.version>2023.0.3</spring.cloud.version>
<!-- Spring Cloud Alibaba 2023.0.x 系列,需与 Spring Cloud 2023.0.x 匹配 [citation:2][citation:9][citation:10] -->
<spring.cloud.alibaba.version>2023.0.1.0</spring.cloud.alibaba.version>
</properties>
......
......
<dependencyManagement>
<!-- 1. 导入 Spring Cloud 的依赖管理 BOM [citation:1][citation:5] -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 2. 导入 Spring Cloud Alibaba 的依赖管理 BOM [citation:6][citation:9] -->
<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>
</dependencies>
</dependencyManagement>
......
......
二、Nacos的服务注册与发现和配置中心
- 为什么需要服务注册与发现?
在微服务架构中会出现跨进程跨主机的服务调用,如何让这个服务之间能互相发现像单体式应用一样提供统一对外的服务调用能力是微服务框架层面需要重点解决的核心问题之一。 在 Spring Cloud 生态中,采用了服务注册与发现模型,来实现微服务之间的互相发现与调用。 - 为什么需要配置中心?
- 传统的开发方式中,这些配置信息通常硬编码到应用程序的代码中,与程序代码一起打包和部署。然而,这种方式有很多缺点,比如配置信息不易维护,只要修改配置就得重新构建和部署等。当有大量应用程序需要管理时,手动维护配置文件会变得非常困难。分布式配置中心提供了一个集中管理和分发配置信息的解决方案。
2)、mvn配置
<!-- 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>
<!-- Spring Cloud Bootstrap 支持 (Spring Boot 3.x 必需) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
3)、bootstrap.yml配置(引导阶段读取,会被application.yml 覆盖相同内容)
properties
spring:
application:
name: provider-server
cloud:
nacos:
# Nacos 服务注册中心地址
discovery:
server-addr: http://127.0.0.1:8848
enabled: true
# 禁用服务注册到 Nacos。如果不想当前应用的服务被注册到服务中心则开启
# register-enabled: false
# Nacos 配置中心地址
config:
server-addr: http://127.0.0.1:8848
file-extension: yaml
# 共享配置
shared-configs:
- data-id: common.yaml
refresh: true
# 优先使用共享配置还是应用独立配置
override-configs: false
# 是否支持配置热更新
refresh-enabled: true
# 加密配置 (如需)
# encrypt-key: your-encrypt-key
# 启用配置导入(优先级高于本地的application.yml配置)
config:
import:
- optional:nacos:provider-server.yaml
- optional:nacos:common.yaml
4)、application.yml配置 (应用启动阶段读取)
properties
server:
port: 8081
spring:
application:
name: provider-server
5)、启动入口添加注解:@EnableDiscoveryClient
java
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
6)、启动后自动注册服务到nacos
java
@RestController
@RequestMapping("/sysUser")
public class SysUserController {
private final ISysUserService sysUserService;
public SysUserController(ISysUserService sysUserService) {
this.sysUserService = sysUserService;
}
@GetMapping("/selectById/{id}")
public SysUser selectById(@PathVariable("id") Long id) {
SysUser user = new SysUser();
user.setNickName("我是服务端的人");
return user;
}
}

7)、nacos配置热更新(注意:不是所有的配置都能热更新,比如数据库配置、日志配置等是在启动阶段加载的,所以热更新是无效的,必须重启程序才会生效)
- 常用方式一:@RefreshScope +@Value
java
@RestController
@RefreshScope // 关键注解:支持热更新
public class OrderController {
@Value("${order.timeout:3000}")
private int timeout;
@Value("${order.discount.enabled:false}")
private boolean discountEnabled;
@GetMapping("/order/config")
public Map<String, Object> getConfig() {
return Map.of(
"timeout", timeout,
"discountEnabled", discountEnabled
);
}
}
- 常用方式二:@ConfigurationProperties
java
@Component
@ConfigurationProperties(prefix = "order") // 自动映射 order.* 配置
@Data
public class OrderProperties {
private int timeout = 3000;
private Discount discount = new Discount();
@Data
public static class Discount {
private boolean enabled = false;
private double rate = 1.0;
}
}
@RestController
public class OrderController {
@Autowired
private OrderProperties orderProperties;
@GetMapping("/order/config")
public OrderProperties getConfig() {
// 配置更新后,orderProperties 会自动更新(无需 @RefreshScope)
return orderProperties;
}
}
三、OpenFeign远程调用 + Sentinel限流、熔断、降级
1)、首先需要连接nacos server去发现服务,同时使用nacos config配置中心管理配置
1)、mvn依赖
xml
<!-- 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>
<!-- Spring Cloud Bootstrap 支持 (Spring Boot 3.x 必需) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!-- Sentinel 流量控制(如需熔断限流) -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- openfeigh 远程调用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- feign 通过服务名的方式远程调用时,默认走负载均衡模式,必须添加loadbalancer-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
2)、bootstrap.yml
properties
spring:
application:
name: customer-server
cloud:
# 接入Sentinel server
sentinel:
transport:
client-ip: 127.0.0.1
port: 8866
dashboard: http://127.0.0.1:8866
nacos:
# Nacos 服务注册中心地址
discovery:
server-addr: http://127.0.0.1:8848
enabled: true
# 禁用服务注册到 Nacos
register-enabled: false
# Nacos 配置中心地址
config:
server-addr: http://127.0.0.1:8848
file-extension: yaml
# 共享配置
shared-configs:
- data-id: common.yaml
refresh: true
# 优先使用共享配置还是应用独立配置
override-configs: false
# 是否支持配置热更新
refresh-enabled: true
# 加密配置 (如需)
# encrypt-key: your-encrypt-key
# 启用配置导入
config:
import:
- optional:nacos:common.yaml
3)、application.yml
properties
server:
port: 8082
spring:
application:
name: customer-server
# 开启feign 对 Sentinel的支持
feign:
sentinel:
enabled: true
4)、启动类
java
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class CustomerApplication {
public static void main(String[] args) {
SpringApplication.run(CustomerApplication.class, args);
}
}
5)、创建FeignClient接口,并通过Sentinel对OpenFeign的整合支持,实现服务降级
- FeignClient接口
java
// 使用openFeign , 自带负载均衡,集成Sentinel服务降级
// name要调用的服务名(注册到nacos中的)、path目标服务的前缀,类似@RequstMapping的path、fallback 目标服务调用失败、熔断、限流等情况导致的服务调用失败的降级类
@FeignClient(name = "provider-server", path = "/sysUser",fallback = SysUserClientFallback.class)
public interface SysUserClient {
@GetMapping("/selectById/{id}")
SysUser selectById(@PathVariable("id") Long id);
}
- 服务降级类:当Feign调用@GetMapping中的服务失败时,会降级到该实现类的内容
java
@Component
public class SysUserClientFallback implements SysUserClient{
@Override
public SysUser selectById(Long id) {
SysUser sysUser = new SysUser();
sysUser.setNickName("fallback user");
return sysUser;
}
}
6)、使用远程服务调用:
java
@RestController
@RequestMapping("/customer/sysUser")
public class SysUserController {
private final SysUserClient sysUserClient;
public SysUserController(SysUserClient sysUserClient) {
this.sysUserClient = sysUserClient;
}
@GetMapping("/selectById/{id}")
public SysUser selectById(@PathVariable("id") Long id) {
return sysUserClient.selectById(id);
}
}
致此,customer的接口请求/customer/sysUser/selectById/1应该能访问到provider-server中对应的接口/sysUser/selectById/1的内容
7)、Sentinel 的限流与熔断,在工程中通过sentinel.transport 的配置接入到Sentinel server时,在Sentinel的控制台就能看到接入的服务,通过控制台即可配置资源的限流、熔断等规则:

四、使用Seata处理分布式事务
- 在分布式系统中一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务节点上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。
- 在Seata的核心概念中,有三个核心角色:
- TC Transaction Coordinator 全局事务协调器,管理全局事务状态,由Seata Server充当
- TM Transaction Manager 发起全局事务,提交或回滚,由服务消费方充当
- RM Resource Manager 管理分支事务,执行本地事务并上报状态,执行数据库操作的每一个业务方
整体流程:
md
│ │
│ 1. 【创建】 │
│ TM 调用 @GlobalTransactional │
│ ↓ │
│ TC 生成 XID: 192.168.1.100:8091:1234567890 │
│ ↓ │
│ XID 绑定到当前线程(ThreadLocal) │
│ │
│ 2. 【传播】 │
│ 服务消费者调用提供者服务 │
│ ↓ │
│ Feign 将 XID 放入请求头 │
│ ↓ │
│ 服务提供者提供者从请求头提取 XID,绑定到本地线程 │
│ │
│ 3. 【注册】 │
│ 提供者服务执行本地事务前 │
│ ↓ │
│ RM 向 TC 注册分支事务(携带 XID) │
│ ↓ │
│ TC 在 branch_table 记录分支关系 │
│ │
│ 4. 【执行】 │
│ 本地事务执行,数据变更记录到 undo_log(关联 XID) │
│ │
│ 5. 【提交/回滚】 │
│ 所有分支执行完毕 │
│ ↓ │
│ TM 通知 TC 提交或回滚(携带 XID) │
│ ↓ │
│ TC 根据 XID 查找所有分支,通知各 RM 执行提交或回滚 │
│ │
│ 6. 【清理】 │
│ undo_log 删除(提交时)或使用(回滚时) │
│ XID 从线程解绑 │
│ │
└─────────────────────────────────────────────────────────────────┘
2)、修改数据源及创建Seata数据源代理:
java
@Configuration
public class DataSourceConfig {
/**
* 创建原始的数据源
* @return
*/
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource(){
return new DruidDataSource();
}
/**
* 使用seata对数据源进行代理,从而进行分布式事务
* @param dataSource
* @return
*/
@Bean
@Primary
public DataSourceProxy dataSourceProxy(DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
}
3)bootstrap.yml
properties
# Seata 配置
seata:
# Seata 应用 ID
application-id: ${spring.application.name}
# 事务组名称
tx-service-group: default_tx_group
service:
# 事务组与集群的映射关系
vgroup-mapping:
default_tx_group: default
# Seata Server 地址
grouplist:
default: 127.0.0.1:8091
# 注册中心配置
registry:
type: file
config:
type: file
4)、消费者请求开启分布式事务
java
@GetMapping("/updateUser/{id}")
@GlobalTransactional(name = "update-user", rollbackFor = Exception.class)
public void updateUser(@PathVariable("id") Long id){
sysUserClient.updateUserNickName(id);
sysUserClient.updateUserEmail(id);
}
五、Spring Cloud Stream + Rabbit/RocketMQ/Kafka
1)、Spring Cloud Stream 提供了消息中间件配置的统一抽象,内部有两个概念:Binder 和 Binding
- Binder: 跟外部消息中间件集成的组件,用来创建 Binding,各消息中间件都有自己的 Binder 实现。
- Binding: 包括 Input Binding 和 Output Binding。
使用Spring Cloud Stream可以无缝切换不同的消息中间件,而不用去修改对应的业务代码对各中间件的API调用
2)、安装对应的消息中间件,如:RabbitMQ,RocketMQ
3)、maven依赖
xml
<!-- spring cloud stream + RabbitMQ-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
4)、application.properties
properties
spring:
application:
name: customer-server
cloud:
stream:
# 配置 Binder(连接 RabbitMQ)
binders:
defaultRabbit:
type: rabbit
environment:
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
# 配置 Binding(通道与交换机的绑定)
bindings:
# 生产者通道
output:
destination: demo-exchange # Exchange 名称
content-type: application/json # 消息格式
binder: defaultRabbit # 使用的 Binder
# 消费者通道
input-in-0:
destination: demo-exchange
content-type: application/json
binder: defaultRabbit
group: customer-group # 相同 group 的实例竞争消费,不设置group则广播所有实例
# RabbitMQ 特有配置
rabbit:
bindings:
output:
producer:
exchangeType: topic # 交换机类型
routing-key-expression: headers['routeTo'] # 从消息头动态获取路由键
input-in-0:
consumer:
exchangeType: topic
bindingRoutingKey: info.* # # 订阅所有 info.x
acknowledge-mode: manual # 手动确认
bindingRoutingKeyDelimiter: ","
auto-bind-dlq: true # 自动创建死信队列
dlq-name: my-queue.dlq # 自定义死信队列名称
republish-to-dlq: true # 失败消息重新发布到 DLQ
max-attempts: 3 # 重试次数
5)、创建处理消息的component,包含了消息发送方法、注册处理消费者通道信息的Bean
java
@Configuration
public class MyMessageComponent {
private static final Logger log = LoggerFactory.getLogger(MyMessageComponent.class);
public static final String OUTPUT_BINDING = "output";
public static final String INPUT_BINDING = "input";
private final StreamBridge streamBridge;
public MyMessageComponent(StreamBridge streamBridge) {
this.streamBridge = streamBridge;
}
public boolean sendMessage(Object payload) {
return sendMessage(payload, null);
}
public boolean sendMessage(Object payload, String routingKey) {
Message<?> message = routingKey != null
? MessageBuilder.withPayload(payload)
.setHeader("routeTo", routingKey)
.build()
: MessageBuilder.withPayload(payload).build();
boolean result = streamBridge.send(OUTPUT_BINDING, message);
log.info("消息发送{}: {}", result ? "成功" : "失败", payload);
return result;
}
/**
* 自动处理所有到input通道的信息
* @return
*/
@Bean
public Consumer<Message<Map<String, Object>>> input() {
return message -> {
Map<String, Object> payload = message.getPayload();
// 获取 路由,用于执行对应逻辑
String routingKey = (String) message.getHeaders().get("amqp_receivedRoutingKey");
// 获取 Channel(用于发送 ACK 命令)
Channel channel = (Channel) message.getHeaders().get("amqp_channel");
// 获取 deliveryTag(消息的唯一标识)
Long deliveryTag = (Long) message.getHeaders().get("amqp_deliveryTag");
try {
log.info("收到消息:路由=>", routingKey);
log.info("收到消息:{}", payload);
if (channel != null && deliveryTag != null) {
channel.basicAck(deliveryTag, false);
log.info("消息确认成功");
}
} catch (Exception e) {
log.error("消息处理失败", e);
try {
if (channel != null && deliveryTag != null) {
channel.basicNack(deliveryTag, false, false);
log.info("消息拒绝,不重新入队");
}
} catch (Exception ex) {
log.error("消息拒绝失败", ex);
}
}
};
}
}
使用示例:
java
myMessageComponent.sendMessage(user,"user.create");
六、分布式定时任务
@SchedulerLock 注解是一个分布式锁的框架,结合@Scheduled 注解,可以保证任务同一时间,在多个节点上只会执行一次。该框架支持多种分布式锁的实现,比如Jdbc、Zookeeper、Redis等。原理如下:

1)、maven依赖
xml
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>6.3.1</version> <!-- 最新版本 -->
</dependency>
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<version>6.3.1</version>
</dependency>
2)、mysql加表
sql
CREATE TABLE shedlock (
name VARCHAR(64) NOT NULL, -- 锁名称(对应任务名)
lock_until TIMESTAMP(3) NOT NULL, -- 锁失效时间
locked_at TIMESTAMP(3) NOT NULL, -- 加锁时间
locked_by VARCHAR(255) NOT NULL, -- 锁持有者标识
PRIMARY KEY (name)
);
3)、在启动类添加注解
java
@SpringBootApplication
@EnableScheduling //开启spring调度
@EnableSchedulerLock(defaultLockAtMostFor = "3m") // 开启调度锁
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
4)、创建配置类
java
@Configuration
public class ScheduledLockConfig {
@Autowired
private DataSource dataSource;
@Bean
public LockProvider lockProvider() {
return new JdbcTemplateLockProvider(JdbcTemplateLockProvider.Configuration.builder()
.withJdbcTemplate(new JdbcTemplate(dataSource))
.withTimeZone(TimeZone.getTimeZone("UTC"))
.build());
}
}
5)、创建定时任务
java
@Component
public class SpringJob {
/**
* 每5分钟跑一次
*/
@Scheduled(cron = "0 */5 * * * ?")
@SchedulerLock(name = "SpringJob.job1", lockAtMostFor = "2m", lockAtLeastFor = "1m")
public void job1() {
System.out.println("time=" + DateTime.now().toString("YYYY-MM-dd HH:mm:ss") + " do job1...");
}
/**
* 每5秒跑一次
*/
@Scheduled(fixedRate = 5000)
@SchedulerLock(name = "SpringJob.job2", lockAtMostFor = "4s", lockAtLeastFor = "4s")
public void job2() {
System.out.println("time=" + DateTime.now().toString("YYYY-MM-dd HH:mm:ss") + " do job2...");
}
/**
* 上次跑完之后隔5秒再跑
* @throws InterruptedException
*/
@Scheduled(fixedDelay = 5000)
@SchedulerLock(name = "SpringJob.job3", lockAtMostFor = "4s", lockAtLeastFor = "4s")
public void job3() throws InterruptedException {
System.out.println("time=" + DateTime.now().toString("YYYY-MM-dd HH:mm:ss") + " do job3...");
Thread.sleep(10000);
}
}
七、网关Spring Cloud Gateway
最佳实践如下,内容涉及多个框架整合,可参考入门教程:Spring Cloud Alibaba Gateway 实战:从零构建高性能服务网关
-
生产环境配置
- 使用 Nacos 配置中心管理路由
- 启用 Sentinel 进行流量控制
- 配置 Redis 集群提高可用性
-
安全加固
- 实现 JWT 鉴权
- 配置 HTTPS
- 限制 CORS 来源
-
性能优化
- 调整 Netty 线程池参数
- 配置合适的连接超时时间
- 启用响应式编程
-
监控告警
- 集成 Prometheus + Grafana
- 配置日志收集(ELK)
- 设置关键指标告警