前置要求:Java基础、Spring Boot基础
学习时长:约3-5天
技术栈:Spring Cloud + Nacos + Gateway + Feign
适用场景:企业级微服务架构
一、Spring Cloud是什么?
Spring Cloud是Java微服务全家桶,提供了一整套微服务解决方案。
| 组件 | 作用 | 替代方案 |
|---|---|---|
| Nacos | 服务注册/配置中心 | Consul、Eureka |
| Gateway | API网关 | Zuul、Kong |
| Feign | 声明式HTTP客户端 | RestTemplate |
| Sentinel | 熔断限流 | Hystrix |
| Seata | 分布式事务 | 2PC、TCC |
二、服务注册与发现(Nacos)
2.1 安装Nacos
# Docker安装
docker run -d --name nacos \
-p 8848:8848 \
-p 9848:9848 \
-e MODE=standalone \
nacos/nacos-server:latest
# 访问:http://localhost:8848/nacos
# 默认账号:nacos/nacos
2.2 服务注册
<!-- pom.xml -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
# application.yml
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
// 启动类
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
三、API网关(Gateway)
3.1 配置网关
# application.yml
spring:
application:
name: gateway-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
- id: product-service
uri: lb://product-service
predicates:
- Path=/api/products/**
server:
port: 8080
3.2 自定义过滤器
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 验证token
try {
String userId = JwtUtils.verify(token.substring(7));
ServerHttpRequest request = exchange.getRequest().mutate()
.header("X-User-Id", userId)
.build();
return chain.filter(exchange.mutate().request(request).build());
} catch (Exception e) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
}
@Override
public int getOrder() {
return -1;
}
}
四、服务间调用(Feign)
4.1 定义Feign客户端
@FeignClient(name = "user-service", fallbackFactory = UserClientFallbackFactory.class)
public interface UserClient {
@GetMapping("/api/users/{id}")
ApiResponse<User> getUser(@PathVariable("id") Long id);
@PostMapping("/api/users")
ApiResponse<User> createUser(@RequestBody CreateUserRequest request);
}
@Component
public class UserClientFallbackFactory implements FallbackFactory<UserClient> {
@Override
public UserClient create(Throwable cause) {
return new UserClient() {
@Override
public ApiResponse<User> getUser(Long id) {
return ApiResponse.error("用户服务不可用");
}
@Override
public ApiResponse<User> createUser(CreateUserRequest request) {
return ApiResponse.error("用户服务不可用");
}
};
}
}
4.2 使用Feign
@Service
public class OrderService {
@Autowired
private UserClient userClient;
public Order createOrder(CreateOrderRequest request) {
// 调用用户服务获取用户信息
ApiResponse<User> userResponse = userClient.getUser(request.getUserId());
if (userResponse.getCode() != 200) {
throw new RuntimeException("获取用户信息失败");
}
User user = userResponse.getData();
// 创建订单
Order order = new Order();
order.setUserId(user.getId());
order.setUserName(user.getUsername());
// ...
return order;
}
}
五、配置中心(Nacos Config)
5.1 配置
# application.yml
spring:
cloud:
nacos:
config:
server-addr: localhost:8848
file-extension: yaml
group: DEFAULT_GROUP
5.2 动态配置
@RestController
@RefreshScope // 支持动态刷新
public class ConfigController {
@Value("${app.name}")
private String appName;
@Value("${app.version}")
private String version;
@GetMapping("/config")
public Map<String, String> getConfig() {
Map<String, String> config = new HashMap<>();
config.put("appName", appName);
config.put("version", version);
return config;
}
}
六、熔断限流(Sentinel)
6.1 安装Sentinel Dashboard
docker run -d --name sentinel \
-p 8858:8858 \
bladex/sentinel-dashboard:latest
# 访问:http://localhost:8858
# 默认账号:sentinel/sentinel
6.2 使用Sentinel
@Service
public class UserService {
@SentinelResource(
value = "getUser",
fallback = "getUserFallback",
blockHandler = "getUserBlockHandler"
)
public User getUser(Long id) {
return userRepository.findById(id).orElse(null);
}
// 降级方法
public User getUserFallback(Long id, Throwable t) {
return new User(0L, "默认用户", "");
}
// 限流方法
public User getUserBlockHandler(Long id, BlockException e) {
throw new RuntimeException("请求被限流");
}
}
七、分布式事务(Seata)
7.1 安装Seata
docker run -d --name seata \
-p 8091:8091 \
-e SEATA_PORT=8091 \
seataio/seata-server:latest
7.2 使用分布式事务
@Service
public class OrderService {
@GlobalTransactional // 开启全局事务
public void createOrder(CreateOrderRequest request) {
// 1. 创建订单
Order order = new Order();
order.setUserId(request.getUserId());
orderMapper.insert(order);
// 2. 扣减库存(调用库存服务)
inventoryClient.deduct(request.getProductId(), request.getQuantity());
// 3. 扣减余额(调用账户服务)
accountClient.debit(request.getUserId(), order.getTotalAmount());
// 如果任何一步失败,所有操作都会回滚
}
}
八、项目结构
my-microservice/
├── gateway-service/ # API网关
├── user-service/ # 用户服务
├── order-service/ # 订单服务
├── product-service/ # 商品服务
├── common/ # 公共模块
│ ├── common-core/ # 核心工具
│ ├── common-redis/ # Redis工具
│ └── common-mybatis/ # MyBatis配置
└── pom.xml
学习建议
- 先理解微服务架构概念
- 掌握Nacos服务注册和配置
- 学会Gateway网关配置
- 掌握Feign服务间调用
- 了解Sentinel熔断限流