在真实项目中,Resilience4j 的使用方式非常灵活,既可以用注解简化开发,也能用代码手动配置实现灵活控制,还能通过配置文件统一管理参数。关于生效范围,也并非只能对单个接口生效,下面我们逐一说明。
一、三种常用使用方式及适用场景
1. 注解形式 —— 最常用(推荐 Spring Boot 项目)
特点
通过注解直接标记需要保护的方法,底层通过 AOP 实现功能,代码侵入性低,配置简单。
使用示例
首先需要在 Spring Boot 项目中添加依赖(以 Maven 为例):
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>1.7.1</version>
</dependency>
然后在接口方法上添加注解:
@Service
public class OrderService {
// 熔断注解:指定熔断实例名和降级方法
@CircuitBreaker(name = "paymentService", fallbackMethod = "paymentFallback")
// 重试注解:指定重试实例名
@Retry(name = "paymentService")
public String callPaymentService(String orderId) {
// 调用支付服务(实际项目中是HTTP调用或RPC调用)
return "支付服务处理订单:" + orderId;
}
// 降级方法(参数和返回值需与原方法一致)
public String paymentFallback(String orderId, Exception e) {
return "订单" + orderId + "暂时无法支付,请稍后重试";
}
}
适用场景
-
大多数 Spring Boot/Spring Cloud 微服务项目
-
不需要动态修改配置逻辑的场景
-
希望代码简洁,减少手动配置的场景
2. 代码配置形式(手动创建 Config)—— 最灵活
特点
通过CircuitBreakerConfig.custom()等代码手动创建配置,可根据业务逻辑动态调整参数(比如根据时间、用户类型修改配置)。
使用示例
@Service
public class UserService {
private final CircuitBreaker userServiceCircuitBreaker;
// 构造方法中初始化熔断配置
public UserService() {
// 动态配置:比如非高峰时段失败阈值设高一点
int failureThreshold = LocalTime.now().isAfter(LocalTime.of(20, 0)) ? 70 : 50;
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(failureThreshold)
.waitDurationInOpenState(Duration.ofSeconds(10))
.build();
this.userServiceCircuitBreaker = CircuitBreaker.of("userService", config);
}
public String queryUser(String userId) {
// 手动用熔断包装调用
return Try.ofSupplier(CircuitBreaker.decorateSupplier(
userServiceCircuitBreaker, () -> "查询用户" + userId + "成功"))
.recover(Exception.class, "查询用户失败")
.get();
}
}
适用场景
-
需要动态调整配置参数的场景(比如根据时段、用户等级修改阈值)
-
非 Spring 环境的项目
-
需要在代码中手动控制熔断 / 重试逻辑的场景
3. 配置文件(yaml)形式 —— 参数集中管理
特点
通过 yaml 或 properties 文件配置参数,无需修改代码即可调整阈值、超时时间等,适合环境差异化配置(开发 / 测试 / 生产用不同参数)。
使用示例
在application.yml中配置:
resilience4j:
circuitbreaker:
instances:
# 支付服务熔断配置
paymentService:
failureRateThreshold: 50
waitDurationInOpenState: 5000
permittedNumberOfCallsInHalfOpenState: 1
retry:
instances:
# 支付服务重试配置
paymentService:
maxAttempts: 3
waitDuration: 1000
retryExceptions:
- java.io.IOException
然后在注解中直接引用实例名(和配置文件中instances下的名称对应):
@CircuitBreaker(name = "paymentService", fallbackMethod = "paymentFallback")
public String callPaymentService(String orderId) {
// 业务逻辑
}
适用场景
-
需要统一管理配置参数的项目
-
不同环境(开发 / 生产)需要不同配置的场景
-
希望通过配置中心(如 Nacos、Apollo)动态刷新参数的场景
二、配置文件(yaml)完整说明
yaml 配置的核心是按 “功能类型→实例名→参数” 的层级结构定义,支持所有核心功能的配置:
resilience4j:
# 熔断配置
circuitbreaker:
instances:
serviceA: # 实例名(注解中name需对应)
failureRateThreshold: 50 # 失败率阈值(百分比)
waitDurationInOpenState: 5000 # 开放状态持续时间(毫秒)
permittedNumberOfCallsInHalfOpenState: 2 # 半开状态允许的调用次数
# 重试配置
retry:
instances:
serviceA:
maxAttempts: 3 # 最大尝试次数(含首次调用)
waitDuration: 1000 # 重试间隔(毫秒)
retryExceptions: # 需要重试的异常
- java.io.IOException
- java.net.SocketTimeoutException
# 限流配置
ratelimiter:
instances:
serviceA:
limitRefreshPeriod: 1000 # 限流刷新周期(毫秒)
limitForPeriod: 10 # 周期内允许的请求数
# 超时配置
timeout:
instances:
serviceA:
timeoutDuration: 2000 # 超时时间(毫秒)
这种配置方式中,instances下的每个 key(如 serviceA)就是实例名,在代码中通过@CircuitBreaker(name = “serviceA”)引用即可生效。
三、如何实现批量 / 全局生效?
Resilience4j 支持通过 “全局默认配置” 和 “批量匹配” 两种方式实现非单个接口生效。
1. 全局默认配置 —— 所有实例共用基础参数
在 yaml 中配置默认值,未单独配置的实例会继承默认参数:
resilience4j:
circuitbreaker:
configs:
default: # 默认配置
failureRateThreshold: 50
waitDurationInOpenState: 5000
instances:
serviceA: # 继承默认配置,可覆盖部分参数
failureRateThreshold: 60 # 覆盖默认的50
serviceB: # 完全使用默认配置
2. 批量匹配接口 —— 通过 AOP 切点实现
在 Spring 项目中,可通过自定义 AOP 切点,对某个包下的所有接口统一应用 Resilience4j 功能。
示例:对com.example.service包下所有方法添加熔断
@Configuration
@Aspect
public class ResilienceGlobalAspect {
private final CircuitBreaker circuitBreaker;
public ResilienceGlobalAspect() {
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.build();
this.circuitBreaker = CircuitBreaker.of("globalService", config);
}
// 切点:匹配com.example.service包下所有公共方法
@Pointcut("execution(* com.example.service..*(..)) && public")
public void servicePointcut() {}
// 环绕通知应用熔断
@Around("servicePointcut()")
public Object wrapWithCircuitBreaker(ProceedingJoinPoint joinPoint) throws Throwable {
// 用熔断包装目标方法调用
Supplier<Object> supplier = () -> {
try {
return joinPoint.proceed();
} catch (Throwable e) {
throw new RuntimeException(e);
}
};
return Try.ofSupplier(CircuitBreaker.decorateSupplier(circuitBreaker, supplier))
.recover(Exception.class, "服务暂时不可用")
.get();
}
}
3. 按业务分组生效 —— 实例名对应业务分组
比如将所有支付相关接口用同一个实例名,共享一套配置:
// 支付相关接口1
@CircuitBreaker(name = "paymentGroup", fallbackMethod = "paymentFallback")
public String createPayment(String orderId) { ... }
// 支付相关接口2
@CircuitBreaker(name = "paymentGroup", fallbackMethod = "paymentFallback")
public String queryPaymentStatus(String paymentId) { ... }
yaml 中只需配置paymentGroup一个实例,两个接口会共用该配置。
四、三种方式的选择建议
使用方式 | 优点 | 缺点 | 推荐场景 |
---|---|---|---|
注解 + yaml 配置 | 简洁、易维护、支持动态配置 | 灵活性稍弱 | 大多数 Spring Boot 微服务项目 |
代码手动配置 | 可动态调整、灵活性极高 | 代码稍繁琐,需手动管理实例 | 需要个性化配置逻辑的场景 |
全局 AOP 配置 | 批量生效,无需逐个标记 | 不适合精细控制单个接口 | 通用服务层批量保护 |
实际项目中通常是 “注解 + yaml” 为主,个别特殊接口用代码手动配置,配合全局默认配置减少重复工作。
五、总结
Resilience4j 在真实项目中并非只能用某一种方式,而是可以根据需求灵活选择:
-
简单场景用 “注解 + yaml”,高效又省心;
-
复杂场景用代码配置,实现动态参数调整;
-
批量生效可通过全局配置、AOP 切点或业务分组实现,无需逐个接口配置。
记住一个原则:能通过配置解决的就不要写代码,需要个性化逻辑的再手动编码,这样既能保证开发效率,又能满足灵活需求。