本文目录导读:

我来为您提供一个完整的Java熔断恢复案例,使用Spring Cloud Circuit Breaker(Resilience4j实现):
项目依赖配置
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Resilience4j Circuit Breaker -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<!-- Resilience4j 核心 -->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>1.7.1</version>
</dependency>
<!-- Actuator 用于监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
配置文件 application.yml
server:
port: 8080
spring:
application:
name: circuit-breaker-demo
# Resilience4j 熔断器配置
resilience4j:
circuitbreaker:
instances:
externalApi:
# 环形缓冲区大小(关闭状态)
ringBufferSizeInClosedState: 10
# 半开状态缓冲区大小
ringBufferSizeInHalfOpenState: 5
# 失败率阈值
failureRateThreshold: 50
# 等待时间(自动从打开到半开)
waitDurationInOpenState: 10000
# 慢调用阈值
slowCallDurationThreshold: 2000
# 慢调用失败率
slowCallRateThreshold: 50
# 记录异常
recordExceptions:
- java.lang.Exception
# 忽略的异常
ignoreExceptions:
- com.example.demo.exception.BusinessException
# 超时配置
timelimiter:
instances:
externalApi:
# 超时时间
timeoutDuration: 3s
# 取消运行中的线程
cancelRunningFuture: true
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: always
服务类 Demo(核心示例)
package com.example.demo.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import io.github.resilience4j.retry.annotation.Retry;
import java.time.LocalDateTime;
@Slf4j
@Service
public class ExternalService {
private final RestTemplate restTemplate;
// 模拟状态变量用于演示
private int callCount = 0;
private int successCount = 0;
public ExternalService() {
this.restTemplate = new RestTemplate();
}
/**
* 带熔断器的外部调用方法
* name 对应 yml 中的配置名称
*/
@CircuitBreaker(name = "externalApi", fallbackMethod = "fallbackGetData")
@Retry(name = "externalApi", fallbackMethod = "fallbackGetData")
@RateLimiter(name = "externalApi", fallbackMethod = "fallbackGetData")
public String getExternalData() {
callCount++;
log.info("=== 开始调用外部服务 (调用次数: {}), 时间: {} ===", callCount, LocalDateTime.now());
// 模拟外部服务调用
String result = callExternalApi();
if (result.contains("成功")) {
successCount++;
log.info("调用成功,当前成功率: {}/{}", successCount, callCount);
return "External Data Result: " + result;
}
throw new RuntimeException("外部服务调用失败");
}
/**
* 模拟外部API调用
* 用于演示不同的调用结果
*/
private String callExternalApi() {
// 这里可以替换成真实的API调用
// 模拟不同的调用场景
// 用于测试:每5次调用中,第3、4次会失败
if (callCount % 5 == 3 || callCount % 5 == 4) {
try {
Thread.sleep(5000); // 模拟慢调用
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
throw new RuntimeException("外部服务响应超时");
}
// 模拟网络异常
if (callCount > 10 && successCount < callCount / 2) {
throw new RuntimeException("Network connection refused");
}
return "成功-" + callCount;
}
/**
* 熔断降级方法
*/
public String fallbackGetData(Throwable t) {
log.error("熔断器触发,降级处理!错误信息: {}", t.getMessage());
return "【降级响应】服务暂时不可用,请稍后重试,降级时间: " + LocalDateTime.now();
}
/**
* 带自定义异常的熔断
*/
@CircuitBreaker(name = "externalApi", fallbackMethod = "fallbackWithCustomException")
public String getUserData(String userId) {
if ("123".equals(userId)) {
throw new IllegalArgumentException("用户ID不存在");
}
return "用户数据: " + userId;
}
public String fallbackWithCustomException(String userId, Throwable t) {
if (t instanceof IllegalArgumentException) {
return "参数错误: " + t.getMessage();
}
return "系统错误,请稍后重试";
}
/**
* 重置熔断器状态(用于测试)
*/
public void resetCircuitBreaker() {
callCount = 0;
successCount = 0;
}
public int getCallCount() {
return callCount;
}
public int getSuccessCount() {
return successCount;
}
}
Controller 控制器
package com.example.demo.controller;
import com.example.demo.service.ExternalService;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import lombok.RequiredArgsConstructor;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class CircuitBreakerController {
private final ExternalService externalService;
private final CircuitBreakerRegistry circuitBreakerRegistry;
/**
* 正常调用接口
*/
@GetMapping("/external")
public String getExternalData() {
return externalService.getExternalData();
}
/**
* 获取熔断器状态
*/
@GetMapping("/breaker/status")
public String getBreakerStatus() {
CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("externalApi");
return String.format(
"状态: %s, 失败率: %.2f%%, 调用次数: %d",
circuitBreaker.getState(),
circuitBreaker.getMetrics().getFailureRate(),
circuitBreaker.getMetrics().getNumberOfSuccessfulCallsWithoutRetry() +
circuitBreaker.getMetrics().getNumberOfFailedCallsWithoutRetry()
);
}
/**
* 重置熔断器
*/
@PostMapping("/breaker/reset")
public String resetBreaker() {
CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("externalApi");
circuitBreaker.reset();
externalService.resetCircuitBreaker();
return "熔断器已重置,当前状态: " + circuitBreaker.getState();
}
/**
* 手动触发打开熔断器
*/
@PostMapping("/breaker/force-open")
public String forceOpenBreaker() {
CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("externalApi");
circuitBreaker.transitionToOpenState();
return "熔断器已强制打开";
}
/**
* 手动关闭熔断器
*/
@PostMapping("/breaker/force-close")
public String forceCloseBreaker() {
CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("externalApi");
circuitBreaker.transitionToCloseState();
return "熔断器已强制关闭";
}
}
自定义配置类
package com.example.demo.config;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.Duration;
@Configuration
public class CircuitBreakerConfig {
/**
* 编程式配置熔断器(可选,也可以使用yml配置)
*/
@Bean
public CircuitBreakerRegistry circuitBreakerRegistry() {
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(50) // 失败率阈值
.waitDurationInOpenState(Duration.ofSeconds(10)) // 等待时间
.ringBufferSizeInClosedState(10) // 关闭状态缓冲区大小
.ringBufferSizeInHalfOpenState(5) // 半开状态缓冲区大小
.slowCallDurationThreshold(Duration.ofSeconds(2)) // 慢调用阈值
.build();
return CircuitBreakerRegistry.of(config);
}
}
全局异常处理
package com.example.demo.exception;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("系统异常: " + e.getMessage());
}
@ExceptionHandler(BusinessException.class)
public ResponseEntity<String> handleBusinessException(BusinessException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body("业务异常: " + e.getMessage());
}
}
测试示例
package com.example.demo.controller;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class CircuitBreakerIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void testCircuitBreakerBehavior() {
// 模拟多次调用触发熔断
for (int i = 0; i < 20; i++) {
ResponseEntity<String> response =
restTemplate.getForEntity("/api/external", String.class);
System.out.println("第 " + (i+1) + " 次调用: " + response.getBody());
// 分段停止
if (i == 4 || i == 9 || i == 14 || i == 19) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 检查熔断器状态
ResponseEntity<String> statusResponse =
restTemplate.getForEntity("/api/breaker/status", String.class);
System.out.println("熔断器状态: " + statusResponse.getBody());
}
}
监控和观察
添加监控端点和查看指标:
package com.example.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Counter;
@RestController
public class MetricsController {
private final MeterRegistry meterRegistry;
public MetricsController(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
@GetMapping("/metrics")
public Object getMetrics() {
return meterRegistry.getMeters().stream()
.map(meter -> meter.getId().getName())
.distinct()
.collect(java.util.stream.Collectors.toList());
}
}
使用说明
- 启动应用:运行主启动类即可看到效果
- 调用接口:
GET /api/external- 测试熔断调用GET /api/breaker/status- 查看熔断器状态POST /api/breaker/reset- 重置熔断器
- 观察日志:通过日志观察熔断器的状态变化
- 访问监控:
http://localhost:8080/actuator/health查看健康状态
这个案例展示了:
- 熔断器的基本配置和使用
- 降级回退机制
- 动态状态管理
- 监控指标
- 测试示例