Spring Cloud 集成
本文档介绍如何在 LCGYL Framework 中集成 Spring Cloud,构建微服务架构。
快速开始
添加依赖
gradle
dependencies {
implementation 'com.lcgyl:lcgyl-spring-cloud:${version}'
implementation 'org.springframework.cloud:spring-cloud-starter-bootstrap'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:2023.0.0"
}
}xml
<dependencies>
<dependency>
<groupId>com.lcgyl</groupId>
<artifactId>lcgyl-spring-cloud</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2023.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>服务注册与发现
Nacos 配置
yaml
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: dev
group: DEFAULT_GROUPEureka 配置
yaml
spring:
application:
name: user-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true服务注册
java
@SpringBootApplication
@EnableDiscoveryClient
@EnableLcgylFramework
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}服务调用
OpenFeign
java
// 添加依赖
// implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
@SpringBootApplication
@EnableFeignClients
public class OrderServiceApplication {
}
// 定义 Feign 客户端
@FeignClient(name = "user-service", fallback = UserClientFallback.class)
public interface UserClient {
@GetMapping("/api/users/{id}")
User getUser(@PathVariable("id") Long id);
@GetMapping("/api/users")
List<User> getUsers(@RequestParam("ids") List<Long> ids);
@PostMapping("/api/users")
User createUser(@RequestBody User user);
}
// 降级处理
@Component
public class UserClientFallback implements UserClient {
@Override
public User getUser(Long id) {
return new User(id, "默认用户", "default@example.com");
}
@Override
public List<User> getUsers(List<Long> ids) {
return Collections.emptyList();
}
@Override
public User createUser(User user) {
throw new ServiceUnavailableException("用户服务不可用");
}
}RestTemplate
java
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
public User getUser(Long id) {
return restTemplate.getForObject(
"http://user-service/api/users/{id}",
User.class,
id
);
}
}WebClient
java
@Configuration
public class WebClientConfig {
@Bean
@LoadBalanced
public WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
}
@Service
public class UserService {
@Autowired
private WebClient.Builder webClientBuilder;
public Mono<User> getUser(Long id) {
return webClientBuilder.build()
.get()
.uri("http://user-service/api/users/{id}", id)
.retrieve()
.bodyToMono(User.class);
}
}配置中心
Nacos 配置中心
yaml
spring:
application:
name: user-service
cloud:
nacos:
config:
server-addr: localhost:8848
file-extension: yaml
namespace: dev
group: DEFAULT_GROUP动态配置
java
@RefreshScope
@RestController
public class ConfigController {
@Value("${app.feature.enabled:false}")
private boolean featureEnabled;
@GetMapping("/config")
public Map<String, Object> getConfig() {
return Map.of("featureEnabled", featureEnabled);
}
}配置监听
java
@Component
public class ConfigChangeListener {
@NacosConfigListener(dataId = "user-service.yaml", groupId = "DEFAULT_GROUP")
public void onConfigChange(String config) {
logger.info("配置变更: {}", config);
// 处理配置变更
}
}服务网关
Gateway 配置
yaml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
- AddRequestHeader=X-Request-Source, gateway
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=1自定义过滤器
java
@Component
public class AuthenticationFilter implements GlobalFilter, Ordered {
@Autowired
private JwtTokenProvider tokenProvider;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = extractToken(exchange.getRequest());
if (token == null || !tokenProvider.validateToken(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 添加用户信息到请求头
String username = tokenProvider.getUsernameFromToken(token);
ServerHttpRequest request = exchange.getRequest().mutate()
.header("X-User-Name", username)
.build();
return chain.filter(exchange.mutate().request(request).build());
}
@Override
public int getOrder() {
return -100;
}
private String extractToken(ServerHttpRequest request) {
String header = request.getHeaders().getFirst("Authorization");
if (header != null && header.startsWith("Bearer ")) {
return header.substring(7);
}
return null;
}
}限流配置
java
@Configuration
public class RateLimiterConfig {
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getHeaders().getFirst("X-User-Name")
);
}
@Bean
public KeyResolver ipKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
);
}
}yaml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@userKeyResolver}"熔断降级
Sentinel 配置
yaml
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080
eager: true熔断规则
java
@PostConstruct
public void initFlowRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("getUserById");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(100);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}降级处理
java
@Service
public class UserService {
@SentinelResource(
value = "getUserById",
blockHandler = "getUserByIdBlockHandler",
fallback = "getUserByIdFallback"
)
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
// 限流处理
public User getUserByIdBlockHandler(Long id, BlockException ex) {
logger.warn("用户查询被限流: {}", id);
return new User(id, "限流用户", "blocked@example.com");
}
// 异常降级
public User getUserByIdFallback(Long id, Throwable ex) {
logger.error("用户查询异常: {}", id, ex);
return new User(id, "降级用户", "fallback@example.com");
}
}Resilience4j
java
@Service
public class UserService {
@CircuitBreaker(name = "userService", fallbackMethod = "getUserFallback")
@RateLimiter(name = "userService")
@Retry(name = "userService")
public User getUser(Long id) {
return userClient.getUser(id);
}
public User getUserFallback(Long id, Exception ex) {
return new User(id, "降级用户", "fallback@example.com");
}
}yaml
resilience4j:
circuitbreaker:
instances:
userService:
slidingWindowSize: 10
failureRateThreshold: 50
waitDurationInOpenState: 10000
ratelimiter:
instances:
userService:
limitForPeriod: 100
limitRefreshPeriod: 1s
retry:
instances:
userService:
maxAttempts: 3
waitDuration: 1000分布式事务
Seata 配置
yaml
seata:
enabled: true
application-id: ${spring.application.name}
tx-service-group: my_tx_group
service:
vgroup-mapping:
my_tx_group: default
grouplist:
default: localhost:8091全局事务
java
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private UserClient userClient;
@Autowired
private InventoryClient inventoryClient;
@GlobalTransactional(name = "createOrder", rollbackFor = Exception.class)
public Order createOrder(OrderRequest request) {
// 1. 扣减库存
inventoryClient.deduct(request.getProductId(), request.getQuantity());
// 2. 扣减余额
userClient.deductBalance(request.getUserId(), request.getTotalAmount());
// 3. 创建订单
Order order = new Order();
order.setUserId(request.getUserId());
order.setProductId(request.getProductId());
order.setQuantity(request.getQuantity());
order.setTotalAmount(request.getTotalAmount());
order.setStatus(OrderStatus.CREATED);
return orderRepository.save(order);
}
}链路追踪
Sleuth + Zipkin
yaml
spring:
sleuth:
sampler:
probability: 1.0
zipkin:
base-url: http://localhost:9411自定义 Span
java
@Service
public class OrderService {
@Autowired
private Tracer tracer;
public Order createOrder(Order order) {
Span span = tracer.nextSpan().name("createOrder").start();
try (Tracer.SpanInScope ws = tracer.withSpan(span)) {
span.tag("orderId", order.getId().toString());
span.tag("userId", order.getUserId().toString());
// 业务逻辑
return orderRepository.save(order);
} finally {
span.end();
}
}
}LCGYL 事件集成
分布式事件
java
@Component
public class DistributedEventPublisher {
@Autowired
private EventBus eventBus;
@Autowired
private StreamBridge streamBridge;
public void publishEvent(Object event) {
// 本地事件
eventBus.publish(event);
// 分布式事件
streamBridge.send("events-out-0", event);
}
}
@Component
public class DistributedEventListener {
@Bean
public Consumer<OrderCreatedEvent> orderCreatedConsumer() {
return event -> {
logger.info("收到分布式事件: {}", event);
// 处理事件
};
}
}最佳实践
1. 服务拆分
✅ 推荐:按业务领域拆分
- user-service
- order-service
- product-service
- payment-service
❌ 不推荐:按技术层拆分
- controller-service
- service-service
- dao-service2. 服务通信
java
// ✅ 推荐:使用 Feign 声明式调用
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/api/users/{id}")
User getUser(@PathVariable Long id);
}
// ❌ 不推荐:硬编码 URL
restTemplate.getForObject("http://localhost:8081/api/users/1", User.class);3. 容错处理
java
// ✅ 推荐:提供降级方案
@FeignClient(name = "user-service", fallback = UserClientFallback.class)
public interface UserClient {
}
// ❌ 不推荐:无降级处理
@FeignClient(name = "user-service")
public interface UserClient {
}常见问题
Q: 如何处理服务间认证?
A: 使用 JWT 或 OAuth2,在 Feign 拦截器中传递 Token。
java
@Component
public class FeignAuthInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
String token = SecurityContextHolder.getContext()
.getAuthentication().getCredentials().toString();
template.header("Authorization", "Bearer " + token);
}
}Q: 如何处理分布式事务?
A:
- 使用 Seata 全局事务
- 使用 Saga 模式
- 使用消息最终一致性
Q: 如何监控微服务?
A:
- Spring Boot Actuator
- Prometheus + Grafana
- Sleuth + Zipkin
下一步
- Spring Boot 集成 - 基础配置
- Spring Security 集成 - 微服务安全
- 监控指标 - 服务监控