Resilience4j 容错保护实战
一、Resilience4j 介绍
在微服务架构中,网络波动、服务宕机是不可避免的。为了保证系统的高可用性,我们需要引入容错机制。Resilience4j 是目前 Java 生态中最受欢迎的容错框架之一。Resilience4j提供了一系列模块化的组件,如断路器(Circuit Breaker)、重试(Retry)、限流器(Rate Limiter)、隔离器(Bulkhead)、缓存(Cache)以及时间器(TimeLimiter),这些组件可以单独使用或组合使用,以应对不同类型的故障场景。
本文将基于一个案例,介绍如何通过 R4jRegistry 和 R4jManager 两个核心类,优雅地管理熔断器(CircuitBreaker)与重试(Retry)机制。
二、Resilience4j实现案例
本方案包含两个核心组件,分别解决了“组件管理”与“任务执行”的问题:
1.创建maven项目、引入pom依赖、配置applicationContext.xml文件

pom依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>java_stu</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.lb</groupId>
<artifactId>sf_stu</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<!-- Resilience4j CircuitBreaker -->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-circuitbreaker</artifactId>
<version>2.1.0</version>
</dependency>
<!-- Resilience4j Retry -->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-retry</artifactId>
<version>2.1.0</version>
</dependency>
<!-- Spring Expression (required by Spring Context 5.x) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.3.31</version>
</dependency>
<!-- Spring Core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.31</version>
</dependency>
<!-- Spring Core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.31</version>
</dependency>
<!-- Spring Beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.3.31</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<!-- Apache Commons Lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
<!-- SLF4J Simple Logger (Fixes "Failed to load class StaticLoggerBinder" warning) -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.36</version>
</dependency>
</dependencies>
</project>
applicationContext.xml文件配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 1. 配置熔断器注册表 -->
<bean id="circuitBreakerRegistry" class="io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry" factory-method="of">
<constructor-arg>
<bean class="io.github.resilience4j.circuitbreaker.CircuitBreakerConfig" factory-method="ofDefaults"/>
</constructor-arg>
</bean>
<!-- 2. 配置重试注册表 -->
<bean id="retryRegistry" class="io.github.resilience4j.retry.RetryRegistry" factory-method="of">
<constructor-arg>
<bean class="io.github.resilience4j.retry.RetryConfig" factory-method="ofDefaults"/>
</constructor-arg>
</bean>
<!-- 3. 配置具体的熔断器实例(供 R4jRegistry.circuitBreaker() 获取) -->
<bean id="myCircuitBreaker" class="io.github.resilience4j.circuitbreaker.CircuitBreaker"
factory-bean="circuitBreakerRegistry" factory-method="circuitBreaker">
<constructor-arg value="myCircuitBreaker"/>
</bean>
<!-- 4. 配置具体的重试实例(供 R4jRegistry.retry() 获取) -->
<bean id="registryRetry" class="io.github.resilience4j.retry.Retry"
factory-bean="retryRegistry" factory-method="retry">
<constructor-arg value="registryRetry"/>
</bean>
</beans>
2. R4jRegistry:组件注册表
R4jRegistry 负责从 Spring IoC 容器中获取并缓存 Resilience4j 的实例。
作用:统一管理全局的 CircuitBreaker 和 Retry 实例。
特点:支持通过名称不区分大小写地查找组件,非常适合企业级多模块共享配置。
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.retry.RetryRegistry;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* R4jRegistry - Resilience4j 注册表工具类
*
* <p>该类提供从 Spring IoC 容器中获取 Resilience4j 熔断器和重试实例的便捷方法。
* 通过静态代码块初始化,确保在类加载时完成注册表的获取。
*
* <p>主要功能:
* <ul>
* <li>获取 CircuitBreaker(熔断器)实例</li>
* <li>获取 Retry(重试)实例</li>
* <li>通过名称不区分大小写的方式查找对应的实例</li>
* </ul>
*
* <p>使用示例:
* <pre>
* {@code
* // 获取熔断器实例
* CircuitBreaker circuitBreaker = R4jRegistry.circuitBreaker("myService");
*
* // 获取重试实例
* Retry retry = R4jRegistry.retry("myRetry");
* }
* </pre>
*
* @author LS
* @see io.github.resilience4j.circuitbreaker.CircuitBreaker
* @see io.github.resilience4j.retry.Retry
*/
public class R4jRegistry {
/** 熔断器注册表,用于管理所有的 CircuitBreaker 实例 */
private static final CircuitBreakerRegistry circuitBreakerRegistry;
/** 重试注册表,用于管理所有的 Retry 实例 */
private static final RetryRegistry retryRegistry;
/**
* 静态代码块:在类加载时初始化注册表
*
* <p>通过 ClassPathXmlApplicationContext 加载 applicationContext.xml 配置文件,
* 从 Spring IoC 容器中获取 CircuitBreakerRegistry 和 RetryRegistry 的 Bean 实例。
*
* <p>注意事项:
* <ul>
* <li>确保类路径下存在 applicationContext.xml 配置文件</li>
* <li>配置文件中需正确配置 CircuitBreakerRegistry 和 RetryRegistry Bean</li>
* </ul>
*/
static {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
circuitBreakerRegistry = context.getBean(CircuitBreakerRegistry.class);
retryRegistry = context.getBean(RetryRegistry.class);
}
/**
* 私有构造函数,防止实例化
*
* <p>该类为工具类,所有方法均为静态方法,无需创建实例。
*/
private R4jRegistry() {
}
/**
* 根据名称获取熔断器实例
*
* <p>从所有注册的 CircuitBreaker 中查找与指定名称匹配的实例(不区分大小写)。
*
* @param name 熔断器名称
* @return 匹配的 CircuitBreaker 实例,如果未找到则返回 null
*
* <p>查找逻辑:
* <ol>
* <li>获取所有已注册的 CircuitBreaker</li>
* <li>使用 Stream API 过滤出名称匹配的实例</li>
* <li>返回第一个匹配的结果,未找到则返回 null</li>
* </ol>
*
* @see io.github.resilience4j.circuitbreaker.CircuitBreaker
*/
public static CircuitBreaker circuitBreaker(String name) {
return circuitBreakerRegistry.getAllCircuitBreakers().stream()
.filter(circuitBreaker -> StringUtils.equalsIgnoreCase(circuitBreaker.getName(), name))
.findFirst()
.orElse(null);
}
/**
* 根据名称获取重试实例
*
* <p>从所有注册的 Retry 中查找与指定名称匹配的实例(不区分大小写)。
*
* @param name 重试实例名称
* @return 匹配的 Retry 实例,如果未找到则返回 null
*
* <p>查找逻辑:
* <ol>
* <li>获取所有已注册的 Retry</li>
* <li>使用 Stream API 过滤出名称匹配的实例</li>
* <li>返回第一个匹配的结果,未找到则返回 null</li>
* </ol>
*
* @see io.github.resilience4j.retry.Retry
*/
public static Retry retry(String name) {
return retryRegistry.getAllRetries().stream()
.filter(retry -> StringUtils.equalsIgnoreCase(retry.getName(), name))
.findFirst()
.orElse(null);
}
}
3. R4jManager:任务管理器
R4jManager 基于装饰器模式实现,它将容错逻辑与业务逻辑解耦。
作用:通过链式调用 acquire() 添加组件,然后调用 run() 方法自动织入容错逻辑。
优势:支持多种函数式接口(Runnable, Consumer, Supplier, Function),满足各种方法签名需求。
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.retry.Retry;
import lombok.SneakyThrows;
import java.util.Stack;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* R4jManager - Resilience4j 管理器
*
* <p>该类提供对 Resilience4j 组件(熔断器、重试)的统一管理和执行功能。
* 通过链式调用添加多个组件,然后使用相应的 run 方法执行目标操作,
* 自动应用所有已添加的组件逻辑。
*
* <p>核心设计:
* <ul>
* <li>使用栈(Stack)存储添加的组件,出栈时按照添加的逆序应用</li>
* <li>支持多种函数式接口:Runnable、Consumer、Supplier、Function</li>
* <li>通过装饰器模式将熔断器和重试逻辑织入目标方法</li>
* </ul>
*
* <p>使用示例:
* <pre>
* {@code
* // 创建管理器并添加熔断器和重试
* R4jManager manager = new R4jManager()
* .acquire(circuitBreaker)
* .acquire(retry);
*
* // 执行无参数的任务
* manager.run(() -> System.out.println("执行任务"));
*
* // 执行带参数的任务
* manager.run("param", param -> process(param));
*
* // 执行有返回值的任务
* String result = manager.run(() -> fetchData());
* }
* </pre>
*
* <p>注意事项:
* <ul>
* <li>组件添加顺序会影响执行顺序(后添加的先执行)</li>
* <li>每次 run 方法调用会清空栈中的所有组件</li>
* <li>不支持同时添加相同类型的多个实例</li>
* </ul>
*
* @author LS
* @see io.github.resilience4j.circuitbreaker.CircuitBreaker
* @see io.github.resilience4j.retry.Retry
*/
public class R4jManager {
/** 存储已获取的组件(CircuitBreaker 或 Retry) */
private final Stack<Object> acquirement;
/**
* 默认构造函数
*
* <p>初始化空的组件栈,等待通过 acquire 方法添加组件。
*/
public R4jManager() {
acquirement = new Stack<>();
}
/**
* 添加熔断器组件
*
* <p>将指定的 CircuitBreaker 添加到组件栈中,支持链式调用。
*
* @param circuitBreaker 要添加的熔断器实例
* @return 当前 R4jManager 实例,支持链式调用
*
* @see io.github.resilience4j.circuitbreaker.CircuitBreaker
*/
public R4jManager acquire(CircuitBreaker circuitBreaker) {
if (circuitBreaker == null) {
throw new IllegalArgumentException("CircuitBreaker instance cannot be null. Please check if it is correctly configured or retrieved.");
}
acquirement.add(circuitBreaker);
return this;
}
/**
* 添加重试组件
*
* <p>将指定的 Retry 添加到组件栈中,支持链式调用。
*
* @param retry 要添加的重试实例
* @return 当前 R4jManager 实例,支持链式调用
*
* @see io.github.resilience4j.retry.Retry
*/
public R4jManager acquire(Retry retry) {
if (retry == null) {
throw new IllegalArgumentException("Retry instance cannot be null. Please check if it is correctly configured or retrieved.");
}
acquirement.push(retry);
return this;
}
/**
* 执行无参数的 Runnable 任务
*
* <p>从组件栈中依次取出所有组件,将其装饰逻辑应用到目标 Runnable 上,
* 最终执行装饰后的任务。组件出栈顺序决定了装饰的应用顺序。
*
* <p>执行流程:
* <ol>
* <li>从栈中弹出组件</li>
* <li>如果是 CircuitBreaker,则应用熔断器装饰器</li>
* <li>如果是 Retry,则应用重试装饰器</li>
* <li>重复直到栈为空</li>
* <li>执行最终装饰后的 Runnable</li>
* </ol>
*
* @param runnable 要执行的目标任务
*
* <p>注意事项:
* <ul>
* <li>此方法会清空组件栈,调用后需要重新添加组件</li>
* <li>如果栈中存在非 CircuitBreaker 或 Retry 类型的对象,将抛出 IllegalArgumentException</li>
* </ul>
*/
public void run(Runnable runnable) {
Runnable cur = runnable;
while (acquirement.size() != 0) {
Object o = acquirement.pop();
if (o instanceof CircuitBreaker) {
cur = ((CircuitBreaker) o).decorateRunnable(cur);
} else if (o instanceof Retry) {
cur = Retry.decorateRunnable((Retry) o, cur);
} else {
throw new IllegalArgumentException("Unknown component type in stack: " + (o == null ? "null" : o.getClass().getName()) + ". Only CircuitBreaker and Retry are supported.");
}
}
cur.run();
}
/**
* 执行带参数的 Consumer 任务
*
* <p>类似于 run(Runnable),但支持传入参数和 Consumer 处理逻辑。
* 所有组件的装饰逻辑会应用到 Consumer 上,最后执行 consumer.accept(param)。
*
* <p>执行流程:
* <ol>
* <li>从栈中弹出组件</li>
* <li>如果是 CircuitBreaker,则应用熔断器装饰器</li>
* <li>如果是 Retry,则应用自定义的重试装饰器(支持异常重试)</li>
* <li>重复直到栈为空</li>
* <li>执行 consumer.accept(param)</li>
* </ol>
*
* @param <T> 参数类型
* @param param 要传递给 Consumer 的参数
* @param consumer 要执行的目标消费者函数
*
* <p>注意事项:
* <ul>
* <li>此方法会清空组件栈,调用后需要重新添加组件</li>
* <li>Retry 装饰器会捕获 RuntimeException 和普通 Exception 进行重试</li>
* </ul>
*/
public <T> void run(T param, Consumer<T> consumer) {
Consumer<T> cur = consumer;
while (acquirement.size() != 0) {
Object o = acquirement.pop();
if (o instanceof CircuitBreaker) {
cur = ((CircuitBreaker) o).decorateConsumer(cur);
} else if (o instanceof Retry) {
cur = decorateConsumer((Retry) o, cur);
} else {
throw new IllegalArgumentException();
}
}
consumer.accept(param);
}
/**
* 执行有返回值的 Supplier 任务
*
* <p>执行无参数但返回结果的任务,所有组件的装饰逻辑会应用到 Supplier 上。
*
* <p>执行流程:
* <ol>
* <li>从栈中弹出组件</li>
* <li>如果是 CircuitBreaker,则应用熔断器装饰器</li>
* <li>如果是 Retry,则应用重试装饰器</li>
* <li>重复直到栈为空</li>
* <li>执行 cur.get() 并返回结果</li>
* </ol>
*
* @param <T> 返回值类型
* @param supplier 要执行的目标供应者函数
* @return Supplier 执行后的结果
*
* <p>注意事项:
* <ul>
* <li>此方法会清空组件栈,调用后需要重新添加组件</li>
* </ul>
*/
public <T> T run(Supplier<T> supplier) {
Supplier<T> cur = supplier;
while (acquirement.size() != 0) {
Object o = acquirement.pop();
if (o instanceof CircuitBreaker) {
cur = ((CircuitBreaker) o).decorateSupplier(cur);
} else if (o instanceof Retry) {
cur = Retry.decorateSupplier((Retry) o, cur);
} else {
throw new IllegalArgumentException();
}
}
return cur.get();
}
/**
* 执行带参数且有返回值的 Function 任务
*
* <p>执行带输入参数并返回结果的任务,所有组件的装饰逻辑会应用到 Function 上。
*
* <p>执行流程:
* <ol>
* <li>从栈中弹出组件</li>
* <li>如果是 CircuitBreaker,则应用自定义的熔断器装饰器(记录执行时间)</li>
* <li>如果是 Retry,则应用重试装饰器</li>
* <li>重复直到栈为空</li>
* <li>执行 cur.apply(param) 并返回结果</li>
* </ol>
*
* @param <I> 输入参数类型
* @param <O> 返回值类型
* @param param 要传递给 Function 的参数
* @param func 要执行的目标函数
* @return Function 执行后的结果
*
* <p>注意事项:
* <ul>
* <li>此方法会清空组件栈,调用后需要重新添加组件</li>
* <li>CircuitBreaker 装饰器会记录方法执行时长并通知熔断器</li>
* </ul>
*/
public <I, O> O run(I param, Function<I, O> func) {
Function<I, O> cur = func;
while (acquirement.size() != 0) {
Object o = acquirement.pop();
if (o instanceof CircuitBreaker) {
cur = decorateFunction((CircuitBreaker) o, cur);
} else if (o instanceof Retry) {
cur = Retry.decorateFunction((Retry) o, cur);
} else {
throw new IllegalArgumentException();
}
}
return cur.apply(param);
}
/**
* 装饰 Consumer 以支持 Retry 重试逻辑
*
* <p>该方法返回一个新的 Consumer,在原始 Consumer 的基础上添加了重试机制。
* 当执行过程中发生异常时,会根据 Retry 配置进行重试。
*
* <p>重试逻辑:
* <ol>
* <li>创建 Retry.Context 上下文对象</li>
* <li>在无限循环中尝试执行 consumer.accept(param)</li>
* <li>如果成功,调用 context.onComplete() 并返回</li>
* <li>如果发生 RuntimeException,调用 context.onRuntimeError(e) 决定是否重试</li>
* <li>如果发生普通 Exception,调用 context.onError(e) 决定是否重试</li>
* </ol>
*
* @param <T> 参数类型
* @param retry 重试实例,提供重试策略和上下文
* @param consumer 原始消费者函数
* @return 装饰后的 Consumer,具备重试能力
*
* <p>注意事项:
* <ul>
* <li>使用 @SneakyThrows 注解处理受检异常,避免方法签名声明 throws</li>
* <li>重试策略由 Retry 实例的配置决定(如重试次数、延迟策略等)</li>
* </ul>
*/
private static <T> Consumer<T> decorateConsumer(Retry retry, Consumer<T> consumer) {
return param -> new Consumer<T>() {
@SneakyThrows
@Override
public void accept(T t) {
Retry.Context<T> context = retry.context();
while (true) {
try {
consumer.accept(param);
context.onComplete();
return;
} catch (RuntimeException e) {
context.onRuntimeError(e);
} catch (Exception e) {
context.onError(e);
}
}
}
};
}
/**
* 装饰 Function 以支持 CircuitBreaker 熔断逻辑
*
* <p>该方法返回一个新的 Function,在原始 Function 的基础上添加了熔断器监控。
* 熔断器会记录方法执行时长和结果,用于判断是否触发熔断。
*
* <p>熔断逻辑:
* <ol>
* <li>调用 circuitBreaker.acquirePermission() 获取执行权限</li>
* <li>记录开始时间戳</li>
* <li>执行 func.apply(param) 获取结果</li>
* <li>计算执行时长并调用 circuitBreaker.onResult() 通知结果</li>
* <li>如果发生异常,调用 circuitBreaker.onError() 通知错误</li>
* </ol>
*
* @param <I> 输入参数类型
* @param <O> 返回值类型
* @param circuitBreaker 熔断器实例,提供熔断策略和状态管理
* @param func 原始函数
* @return 装饰后的 Function,具备熔断监控能力
*
* <p>注意事项:
* <ul>
* <li>如果熔断器处于打开状态,acquirePermission() 可能抛出异常阻止执行</li>
* <li>执行时长用于熔断器的慢调用检测</li>
* </ul>
*/
private static <I, O> Function<I, O> decorateFunction(
CircuitBreaker circuitBreaker,
Function<I, O> func
) {
return param -> {
circuitBreaker.acquirePermission();
long start = circuitBreaker.getCurrentTimestamp();
long duration;
try {
O result = func.apply(param);
duration = circuitBreaker.getCurrentTimestamp() - start;
circuitBreaker.onResult(duration, circuitBreaker.getTimestampUnit(), result);
return result;
} catch (Exception e) {
duration = circuitBreaker.getCurrentTimestamp() - start;
circuitBreaker.onError(duration, circuitBreaker.getTimestampUnit(), e);
throw e;
}
};
}
}
场景演示
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.retry.RetryConfig;
import java.time.Duration;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 使用 R4jManager 和 R4jRegistry 实现重试机制的示例
*
* <p>演示如何通过 R4jRegistry 获取组件实例,
* 再通过 R4jManager 统一管理并执行任务。
*
* <p>两种方式对比:
* <ul>
* <li>方式 1(场景 1-5):直接创建组件实例(推荐,简单直接)</li>
* <li>方式 2(场景 6):通过 R4jRegistry 从 Spring 容器获取(适合企业级项目)</li>
* </ul>
*
* <p>核心优势:
* <ul>
* <li>链式调用:acquire() 方法支持流畅的 API 设计</li>
* <li>统一接口:R4jManager 提供多种 run() 重载方法</li>
* <li>组件复用:可轻松组合 CircuitBreaker 和 Retry</li>
* </ul>
*
* @author LS
* @see R4jManager
* @see R4jRegistry
* @see RetryExample
*/
public class R4jManagerRetryExample {
/** 记录调用次数 */
private static final AtomicInteger callCounter = new AtomicInteger(0);
public static void main(String[] args) {
System.out.println("========== 使用 R4jManager 实现重试机制 ==========\n");
// 1. 创建自定义重试配置
RetryConfig retryConfig = RetryConfig.<String>custom()
.maxAttempts(5) // 最多尝试 5 次
.waitDuration(Duration.ofSeconds(1)) // 每次间隔 1 秒
.retryOnException(e -> e instanceof RuntimeException) // 仅重试运行时异常
.ignoreExceptions(IllegalArgumentException.class) // 忽略非法参数异常
.build();
// 2. 创建 Retry 实例
Retry retry = Retry.of("networkCall", retryConfig);
// 3. 演示场景 1:使用 R4jManager 执行 Supplier(有返回值)
System.out.println("【场景 1】模拟网络抖动(第 3 次成功)");
System.out.println("使用 R4jManager.run(Supplier) 方法");
callCounter.set(0);
try {
String result = new R4jManager()
.acquire(retry)
.run(() -> simulateUnstableNetwork());
System.out.println("最终结果: " + result);
System.out.println("总调用次数: " + callCounter.get());
} catch (Exception e) {
System.out.println("重试耗尽,最终失败: " + e.getMessage());
System.out.println("总调用次数: " + callCounter.get());
}
System.out.println();
printSeparator();
System.out.println();
// 4. 演示场景 2:使用 R4jManager 执行 Function(带参数有返回值)
System.out.println("【场景 2】模拟持续故障(带参数调用)");
System.out.println("使用 R4jManager.run(param, Function) 方法");
callCounter.set(0);
String userId = "user123";
try {
String result = new R4jManager()
.acquire(retry)
.run(userId, (java.util.function.Function<String, String>) id -> simulatePersistentFailureWithParam(id));
System.out.println("最终结果: " + result);
} catch (Exception e) {
System.out.println("重试耗尽,最终失败: " + e.getMessage());
System.out.println("总调用次数: " + callCounter.get());
}
System.out.println();
printSeparator();
System.out.println();
// 5. 演示场景 3:使用 R4jManager 执行 Consumer(带参数无返回值)
System.out.println("【场景 3】模拟非法参数异常(不重试)");
System.out.println("使用 R4jManager.run(param, Consumer) 方法");
callCounter.set(0);
try {
new R4jManager()
.acquire(retry)
.run("testParam", (java.util.function.Consumer<String>) param -> simulateIllegalArgumentWithParam(param));
System.out.println("执行成功");
} catch (Exception e) {
System.out.println("异常类型: " + e.getClass().getSimpleName());
System.out.println("异常信息: " + e.getMessage());
System.out.println("调用次数: " + callCounter.get() + " (被忽略的异常不会重试)");
}
System.out.println();
printSeparator();
System.out.println();
// 6. 演示场景 4:使用 R4jManager 执行 Runnable(无参数无返回值)
System.out.println("【场景 4】模拟网络抖动(无返回值)");
System.out.println("使用 R4jManager.run(Runnable) 方法");
callCounter.set(0);
try {
new R4jManager()
.acquire(retry)
.run(() -> {
simulateUnstableNetwork();
System.out.println(" 🎉 任务执行完成!");
});
System.out.println("总调用次数: " + callCounter.get());
} catch (Exception e) {
System.out.println("重试耗尽,最终失败: " + e.getMessage());
}
System.out.println();
printSeparator();
System.out.println();
// 7. 演示场景 5:组合使用 CircuitBreaker + Retry
System.out.println("【场景 5】组合使用熔断器 + 重试");
System.out.println("先重试(应对临时故障),后熔断(防止雪崩)");
// 创建默认熔断器
io.github.resilience4j.circuitbreaker.CircuitBreaker circuitBreaker =
io.github.resilience4j.circuitbreaker.CircuitBreaker.ofDefaults("myCircuitBreaker");
callCounter.set(0);
try {
String result = new R4jManager()
.acquire(circuitBreaker) // 后添加,先执行(外层)
.acquire(retry) // 先添加,后执行(内层)
.run(() -> simulateUnstableNetwork());
System.out.println("最终结果: " + result);
System.out.println("总调用次数: " + callCounter.get());
System.out.println("熔断器状态: " + circuitBreaker.getState());
} catch (Exception e) {
System.out.println("失败: " + e.getMessage());
System.out.println("熔断器状态: " + circuitBreaker.getState());
}
System.out.println();
printSeparator();
System.out.println();
// 8. 演示场景 6:使用 R4jRegistry 获取组件实例(企业级方式)
System.out.println("【场景 6】使用 R4jRegistry 获取组件实例");
System.out.println("说明:通过 R4jRegistry 从 Spring 容器获取已配置的组件\n");
try {
// 方式 A:通过 R4jRegistry 从 Spring 容器获取(当前已启用)
Retry retryFromRegistry = R4jRegistry.retry("registryRetry");
CircuitBreaker cbFromRegistry = R4jRegistry.circuitBreaker("myCircuitBreaker");
if (retryFromRegistry == null || cbFromRegistry == null) {
throw new RuntimeException("Failed to retrieve components from R4jRegistry. Check applicationContext.xml.");
}
System.out.println("通过 R4jRegistry 获取组件成功!");
System.out.println("使用 R4jManager 执行任务:");
callCounter.set(0);
String result = new R4jManager()
.acquire(cbFromRegistry)
.acquire(retryFromRegistry)
.run(() -> simulateUnstableNetwork());
System.out.println("最终结果: " + result);
System.out.println("总调用次数: " + callCounter.get());
} catch (Exception e) {
System.out.println("异常: " + e.getMessage());
e.printStackTrace();
}
}
/**
* 模拟不稳定的网络连接(前 2 次失败,第 3 次成功)
*/
private static String simulateUnstableNetwork() {
int attempt = callCounter.incrementAndGet();
System.out.println(" 第 " + attempt + " 次调用...");
if (attempt < 3) {
System.out.println(" ❌ 网络超时,抛出异常");
throw new RuntimeException("Connection timeout");
}
System.out.println(" ✅ 连接成功");
return "Success from attempt " + attempt;
}
/**
* 模拟持续故障(带参数版本)
*/
private static String simulatePersistentFailureWithParam(String userId) {
int attempt = callCounter.incrementAndGet();
System.out.println(" 第 " + attempt + " 次调用,用户: " + userId);
System.out.println(" ❌ 服务不可用");
throw new RuntimeException("Service unavailable for user: " + userId);
}
/**
* 模拟非法参数异常(带参数版本)
*/
private static void simulateIllegalArgumentWithParam(String param) {
int attempt = callCounter.incrementAndGet();
System.out.println(" 第 " + attempt + " 次调用,参数: " + param);
System.out.println(" ❌ 参数错误");
throw new IllegalArgumentException("Invalid parameter: " + param);
}
/**
* 打印分隔线(兼容 Java 8)
*/
private static void printSeparator() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 50; i++) {
sb.append('=');
}
System.out.println(sb.toString());
}
}
运行结果

更多推荐



所有评论(0)