断路器模式通过监控业务调用的健康状态,在依赖服务出现异常时自动切断调用链路,避免无效请求持续消耗资源,同时保护关键业务变量不被异常数据污染。结合Lambda表达式可以大幅简化断路器的调用逻辑,让业务代码更聚焦于核心逻辑本身。

断路器模式核心原理
断路器主要有三种状态,不同状态下的处理逻辑不同:
- 关闭状态:正常处理业务请求,当请求失败率超过阈值时切换到打开状态
- 打开状态:直接拒绝所有请求,执行预设的 fallback 逻辑,经过设定的休眠时间后切换到半开状态
- 半开状态:允许少量试探请求,若请求成功则切换回关闭状态,失败则再次切换到打开状态
基于Lambda表达式的断路器实现
我们可以将断路器的核心逻辑封装为一个通用方法,通过Lambda表达式接收业务执行逻辑和 fallback 逻辑,实现业务变量的保护。
断路器核心类实现
首先定义断路器的状态枚举和核心配置类:
// 断路器状态枚举
enum CircuitState {
CLOSED, OPEN, HALF_OPEN
}
// 断路器配置类
class CircuitBreakerConfig {
// 失败率阈值,超过该值切换到打开状态
private double failureRateThreshold;
// 最小请求数,达到该数量后才计算失败率
private int minimumRequestCount;
// 打开状态休眠时间,单位毫秒
private long sleepWindowMillis;
// 半开状态允许的最大请求数
private int halfOpenMaxRequestCount;
public CircuitBreakerConfig(double failureRateThreshold, int minimumRequestCount, long sleepWindowMillis, int halfOpenMaxRequestCount) {
this.failureRateThreshold = failureRateThreshold;
this.minimumRequestCount = minimumRequestCount;
this.sleepWindowMillis = sleepWindowMillis;
this.halfOpenMaxRequestCount = halfOpenMaxRequestCount;
}
// getter方法省略
}
断路器核心逻辑实现
接下来实现断路器的核心处理逻辑,通过Lambda表达式接收业务调用和 fallback 逻辑:
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Supplier;
public class LambdaCircuitBreaker {
private final CircuitBreakerConfig config;
private CircuitState state = CircuitState.CLOSED;
// 总请求数
private final AtomicInteger totalRequestCount = new AtomicInteger(0);
// 失败请求数
private final AtomicInteger failedRequestCount = new AtomicInteger(0);
// 半开状态已处理请求数
private final AtomicInteger halfOpenRequestCount = new AtomicInteger(0);
// 打开状态切换时间
private final AtomicLong openStateTimestamp = new AtomicLong(0);
public LambdaCircuitBreaker(CircuitBreakerConfig config) {
this.config = config;
}
/**
* 执行受保护的逻辑
* @param businessLogic 业务逻辑Lambda,返回需要保护的关键业务变量
* @param fallbackLogic fallback逻辑Lambda,业务失败时返回的默认值
* @return 业务变量结果
*/
public <T> T execute(Supplier<T> businessLogic, Supplier<T> fallbackLogic) {
// 检查状态是否需要转换
checkStateTransition();
if (state == CircuitState.OPEN) {
// 打开状态直接执行fallback
return fallbackLogic.get();
}
if (state == CircuitState.HALF_OPEN) {
// 半开状态检查是否超过允许的最大请求数
if (halfOpenRequestCount.incrementAndGet() > config.getHalfOpenMaxRequestCount()) {
halfOpenRequestCount.decrementAndGet();
return fallbackLogic.get();
}
}
// 执行业务逻辑
totalRequestCount.incrementAndGet();
try {
T result = businessLogic.get();
// 业务执行成功,处理半开状态逻辑
if (state == CircuitState.HALF_OPEN) {
resetToClosedState();
}
return result;
} catch (Exception e) {
// 业务执行失败
failedRequestCount.incrementAndGet();
if (state == CircuitState.HALF_OPEN) {
// 半开状态失败,切换回打开状态
state = CircuitState.OPEN;
openStateTimestamp.set(System.currentTimeMillis());
}
return fallbackLogic.get();
}
}
/**
* 检查状态转换
*/
private void checkStateTransition() {
if (state == CircuitState.OPEN) {
// 检查休眠时间是否到期
long currentMillis = System.currentTimeMillis();
if (currentMillis - openStateTimestamp.get() >= config.getSleepWindowMillis()) {
state = CircuitState.HALF_OPEN;
halfOpenRequestCount.set(0);
}
} else if (state == CircuitState.CLOSED) {
// 检查失败率是否超过阈值
int currentTotal = totalRequestCount.get();
if (currentTotal >= config.getMinimumRequestCount()) {
double failureRate = (double) failedRequestCount.get() / currentTotal;
if (failureRate >= config.getFailureRateThreshold()) {
state = CircuitState.OPEN;
openStateTimestamp.set(System.currentTimeMillis());
}
}
}
}
/**
* 重置到关闭状态
*/
private void resetToClosedState() {
state = CircuitState.CLOSED;
totalRequestCount.set(0);
failedRequestCount.set(0);
halfOpenRequestCount.set(0);
}
}
业务场景使用示例
假设我们需要保护一个获取用户账户余额的关键业务变量,当依赖的账户服务出现故障时,返回默认的缓存余额,避免业务中断:
public class BusinessDemo {
// 模拟账户服务,有50%概率抛出异常
public static Integer getAccountBalanceFromRemote(String userId) {
if (Math.random() > 0.5) {
throw new RuntimeException("账户服务调用失败");
}
return 1000; // 模拟正常返回的余额
}
// 本地缓存的默认余额
public static Integer getDefaultBalance(String userId) {
return 500;
}
public static void main(String[] args) {
// 初始化断路器配置:失败率阈值50%,最少10个请求,休眠3秒,半开状态最多2个请求
CircuitBreakerConfig config = new CircuitBreakerConfig(0.5, 10, 3000, 2);
LambdaCircuitBreaker circuitBreaker = new LambdaCircuitBreaker(config);
String userId = "user_123";
// 批量模拟业务调用
for (int i = 0; i < 20; i++) {
Integer balance = circuitBreaker.execute(
// 业务逻辑Lambda,返回需要保护的关键业务变量
() -> getAccountBalanceFromRemote(userId),
// fallback逻辑Lambda,失败时返回默认值
() -> getDefaultBalance(userId)
);
System.out.println("第" + (i + 1) + "次调用,账户余额:" + balance);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
方案优势总结
通过Lambda表达式实现断路器模式保护关键业务变量,有以下几个明显优势:
- 代码简洁:业务逻辑和 fallback 逻辑通过Lambda表达式内联定义,不需要额外定义接口实现类
- 灵活度高:可以根据不同的业务场景,动态传入不同的业务执行逻辑和 fallback 逻辑,适配多种保护需求
- 侵入性低:业务代码只需要关注核心逻辑,断路器的状态管理、失败统计等逻辑完全封装在断路器内部
- 可扩展性强:如果需要增加新的断路器特性,比如请求超时控制,只需要在
execute方法中扩展逻辑,不需要修改业务调用方的代码
在实际使用中,可以根据业务需求调整断路器的配置参数,比如降低失败率阈值提升保护灵敏度,或者延长休眠时间减少无效试探请求,让断路器更好地适配自身业务场景。