SpringBoot 4.0新特性Resilience重试机制和并发限制

📅 发布时间:2026/7/7 8:05:41 👁️ 浏览次数:
SpringBoot 4.0新特性Resilience重试机制和并发限制
SpringBoot 4.0新特性解析Resilience之失败重试从Spring 7.0版本开始Spring Framework核心模块集成了常用的Resilience弹性相关功能主要包括对方法调用的失败重试支持以及并发控制支持。作为默认依赖Spring 7.0的SpringBoot 4.0自然也就具备了这些强大的弹性能力。本文将重点介绍SpringBoot 4.0中的失败重试特性下一篇将深入探讨并发控制。一、注解式失败重试RetryableRetryable注解提供了一种声明式的方式来实现方法的重试逻辑。它可以标注在单个方法上为该方法设置特定的重试策略也可以标注在类上为类中所有通过代理调用的方法统一指定重试特性。1. 快速上手两步开启重试第一步在启动类启用弹性方法支持使用EnableResilientMethods注解开启Spring的弹性方法处理能力。EnableResilientMethodsSpringBootApplicationpublicclassSpringboot4Application{publicstaticvoidmain(String[]args){SpringApplication.run(Springboot4Application.class,args);}}第二步在业务方法上添加Retryableimportorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;importorg.springframework.retry.annotation.Retryable;RestControllerpublicclassRetryController{privatestaticfinalLoggerlogLoggerFactory.getLogger(RetryController.class);RetryableGetMapping(path/demo)publicStringdemo(){log.info(RetryController demo 被调用);// 模拟一个运行时异常触发重试inta1/0;returndemo;}}默认重试行为触发条件方法抛出任何类型的异常。重试次数初始调用失败后最多进行3 次重试尝试maxRetries 3。因此如果业务方法持续失败总计会被调用1初始 3重试 4 次。重试间隔每次重试之间默认间隔1 秒delay 1000ms。2. 自定义重试策略Retryable提供了丰富的属性允许开发者精细控制重试行为。属性类型描述默认值maxRetriesint最大重试次数不包含初始调用。3delaylong初次调用失败后到第一次重试之间的基础延迟时长毫秒。1000(1秒)maxDelaylong任何一次重试尝试的最大延迟时长毫秒。用于限制因multiplier或jitter导致的延迟过度增长。0(不限制)multiplierdouble用于计算下一次重试延迟的倍数。下一次延迟 上一次延迟 *multiplier。1.0(固定间隔)jitterlong为每次重试延迟添加的随机抖动值毫秒。实际延迟会在[计算延迟 - jitter, 计算延迟 jitter]范围内浮动但不会低于delay或高于maxDelay。0(无抖动)示例复杂重试策略Retryable(maxRetries3,delay1000,maxDelay5000,multiplier3,jitter100)GetMapping(path/demo)publicStringdemo(){// ... }运行日志分析2026-01-22T15:37:13 INFO -- [8080-exec-1] RetryController : RetryController demo // 初始调用 2026-01-22T15:37:14 INFO -- [8080-exec-1] RetryController : RetryController demo // 第1次重试延迟1秒 2026-01-22T15:37:17 INFO -- [8080-exec-1] RetryController : RetryController demo // 第2次重试延迟 1秒 * 3 3秒 2026-01-22T15:37:22 INFO -- [8080-exec-1] RetryController : RetryController demo // 第3次重试延迟 3秒 * 3 9秒但因maxDelay5秒实际延迟5秒 2026-01-22T15:37:22 ERROR -- [8080-exec-1] [dispatcherServlet]: Servlet.service() for... // 重试次数耗尽最终抛出异常注意在整个重试过程中原始请求线程会一直阻塞直到重试耗尽并抛出最终异常。这意味着接口的响应时间可能会显著增加如上例总耗时超过8秒。3. 自定义触发重试的异常类型默认情况下所有异常都会触发重试。您可以通过以下属性精确控制哪些异常应该或不应该触发重试。属性类型描述优先级includesClass? extends Throwable[]指定应触发重试的异常类型。中excludesClass? extends Throwable[]指定不应触发重试的异常类型。高predicateClass? extends MethodRetryPredicate通过自定义MethodRetryPredicate实现类进行更复杂的条件判断。低示例排除特定异常Retryable(includesRuntimeException.class,// 包含所有RuntimeException及其子类excludesArithmeticException.class// 但排除ArithmeticException)GetMapping(path/demo)publicStringdemo(){log.info(RetryController demo);inta1/0;// 抛出ArithmeticException被excludes命中**不会触发重试**returndemo;}二、编程式失败重试RetryTemplate与声明式的Retryable不同RetryTemplate提供了一套API允许您以编程的方式对任意代码块进行重试控制。使用RetryTemplate时无需在启动类上添加EnableResilientMethods注解。1. 基础用法importorg.springframework.retry.support.RetryTemplate;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;RestControllerpublicclassRetryController{GetMapping(path/demo2)publicStringdemo2()throwsException{// 1. 创建RetryTemplate实例RetryTemplateretryTemplatenewRetryTemplate();// 2. 使用execute方法执行需要重试的逻辑returnretryTemplate.execute(context-{log.info(RetryController demo2 被调用);inta1/0;// 模拟异常returndemo2;});}}RetryTemplate默认的重试策略与Retryable一致重试所有异常最多重试3次每次间隔1秒。2. 自定义重试策略您可以通过构建RetryPolicy对象来精细控制RetryTemplate的行为。importorg.springframework.retry.RetryPolicy;importorg.springframework.retry.support.RetryTemplate;importjava.time.Duration;GetMapping(path/demo2)publicStringdemo2()throwsException{// 1. 构建自定义的RetryPolicyRetryPolicyretryPolicyRetryPolicy.builder().maxRetries(3)// 最大重试次数.delay(Duration.ofMillis(1000))// 基础延迟.maxDelay(Duration.ofMillis(5000))// 最大延迟.multiplier(3)// 延迟倍数.jitter(Duration.ofMillis(100))// 抖动时间.includes(RuntimeException.class)// 包含的异常.excludes(ArithmeticException.class)// 排除的异常.build();// 2. 将策略注入到RetryTemplateRetryTemplateretryTemplatenewRetryTemplate(retryPolicy);// 3. 执行需要重试的代码returnretryTemplate.execute(context-{log.info(RetryController demo2 被调用);inta1/0;// 模拟ArithmeticException根据策略此异常被排除不会重试returndemo2;});}SpringBoot 4.0 内置的失败重试功能为构建健壮的微服务应用提供了强大而便捷的支持Retryable注解适用于大多数场景通过声明式配置快速、简洁地为特定方法或类添加重试能力。RetryTemplate编程式API提供了更高的灵活性允许在代码块级别动态控制重试逻辑适用于更复杂的业务场景。两种方式都支持精细化的策略配置包括重试次数、动态延迟、异常过滤等能够有效应对网络抖动、临时性服务不可用等问题提升应用的容错性和用户体验。SpringBoot 4.0新特性解析Resilience之并发限制继上一篇文章介绍了失败重试特性后今天我们来学习SpringBoot 4.0中另一个重要的弹性能力——并发限制。通过ConcurrencyLimit注解我们可以轻松控制方法的并发访问数量实现简易但高效的限流功能。一、注解式并发限制ConcurrencyLimitConcurrencyLimit注解与Retryable类似既可以标注在单个方法上为特定方法设置并发限制也可以标注在类上为类中所有通过代理调用的方法统一设置并发限制。1. 快速上手两步开启并发限制第一步在启动类启用弹性方法支持与重试特性共享同一个开关注解EnableResilientMethodsSpringBootApplicationpublicclassSpringboot4Application{publicstaticvoidmain(String[]args){SpringApplication.run(Springboot4Application.class,args);}}第二步在业务方法上添加ConcurrencyLimitimportorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;importorg.springframework.resilience.concurrency.annotation.ConcurrencyLimit;RestControllerRequestMapping(/api/concurrency-limit)publicclassConcurrencyLimitController{privatestaticfinalLoggerlogLoggerFactory.getLogger(ConcurrencyLimitController.class);ConcurrencyLimit(limit1)GetMapping(path/demo)publicStringdemo()throwsInterruptedException{log.info(ConcurrencyLimitController demo 被调用);// 模拟业务处理耗时Thread.sleep(1000);returndemo - LocalDateTime.now();}}limit 1表示该方法同时只允许1个并发访问。当超过限制的并发请求到来时请求线程会阻塞等待直到前面的请求处理完毕释放许可。2. 效果测试下面通过一个并发测试来验证限流效果publicstaticvoidmain(String[]args)throwsException{System.out.println(start at LocalDateTime.now());intthreadCount5;CountDownLatchstartnewCountDownLatch(1);CountDownLatchstopnewCountDownLatch(threadCount);// 创建5个并发线程for(inti0;ithreadCount;i){newThread(()-{try{start.await();// 等待统一启动信号StringresnewRestTemplate().getForObject(http://localhost:8080/api/concurrency-limit/demo,String.class);System.out.println(res);stop.countDown();}catch(Exceptione){e.printStackTrace();}}).start();}// 统一启动所有线程start.countDown();stop.await();// 等待所有线程完成System.out.println(end at LocalDateTime.now());}运行结果分析start at 2026-01-23T12:52:42.123 // 服务端日志 - 每秒处理一个请求 2026-01-23T12:52:43 INFO -- [nio-exec-4] ConcurrencyLimitController : demo 被调用 // 第1个请求 2026-01-23T12:52:44 INFO -- [nio-exec-2] ConcurrencyLimitController : demo 被调用 // 第2个请求 2026-01-23T12:52:45 INFO -- [nio-exec-5] ConcurrencyLimitController : demo 被调用 // 第3个请求 2026-01-23T12:52:46 INFO -- [nio-exec-3] ConcurrencyLimitController : demo 被调用 // 第4个请求 2026-01-23T12:52:47 INFO -- [nio-exec-1] ConcurrencyLimitController : demo 被调用 // 第5个请求 // 客户端响应时间 demo - 2026-01-23T12:52:43 demo - 2026-01-23T12:52:44 demo - 2026-01-23T12:52:45 demo - 2026-01-23T12:52:46 demo - 2026-01-23T12:52:47 end at 2026-01-23T12:52:47.456由于接口只允许1个并发5个请求被串行处理每个请求耗时1秒总执行时长超过5秒。这验证了并发限制功能确实生效了。3. 注解属性详解ConcurrencyLimit注解主要包含以下属性属性类型描述默认值limitint最大并发访问数Integer.MAX_VALUE(不限制)timeoutint获取许可的超时时间毫秒-1(无限等待)queueCapacityint等待队列容量Integer.MAX_VALUE超时配置示例ConcurrencyLimit(limit1,timeout100)GetMapping(path/demo-with-timeout)publicStringdemoWithTimeout()throwsInterruptedException{log.info(demoWithTimeout 被调用);Thread.sleep(200);// 模拟处理耗时returndemo-with-timeout;}当并发超过限制时等待线程最多等待100毫秒如果超时仍无法获取许可将抛出ConcurrencyThrottleTimeoutException异常。二、实现原理与编程式控制ConcurrencyLimit的背后是ConcurrencyThrottleSupport类它是Spring框架提供的并发控制支持类。除了使用注解我们也可以通过编程方式手动实现并发控制。1. 使用SyncTaskExecutor实现并发限制SyncTaskExecutor内部使用了ConcurrencyThrottleSupport来实现并发控制importorg.springframework.core.task.SyncTaskExecutor;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;RestControllerpublicclassConcurrencyLimitController{// 创建配置了并发限制的SyncTaskExecutorprivateSyncTaskExecutortaskExecutornewSyncTaskExecutor(){{// 设置最大并发数为1this.setConcurrencyLimit(1);}};GetMapping(path/demo2)publicStringdemo2()throwsException{// 通过execute方法执行任务自动受并发限制控制returntaskExecutor.execute(()-{log.info(ConcurrencyLimitController demo2 被调用);Thread.sleep(1000);// 模拟业务处理returndemo2 - LocalDateTime.now();});}}2. 直接使用ConcurrencyThrottleSupport如果需要更精细的控制可以直接使用ConcurrencyThrottleSupportimportorg.springframework.util.ConcurrencyThrottleSupport;RestControllerpublicclassConcurrencyLimitController{privatefinalConcurrencyThrottleSupportthrottlenewConcurrencyThrottleSupport();publicConcurrencyLimitController(){throttle.setConcurrencyLimit(1);// 设置并发限制}GetMapping(path/demo3)publicStringdemo3()throwsException{try{// 尝试获取许可throttle.beforeAccess();// 业务逻辑log.info(ConcurrencyLimitController demo3 被调用);Thread.sleep(1000);returndemo3 - LocalDateTime.now();}finally{// 释放许可throttle.afterAccess();}}}3. 与Async结合使用并发限制可以与Async异步执行结合实现更复杂的场景RestControllerpublicclassConcurrencyLimitController{Async// 异步执行ConcurrencyLimit(limit2)// 控制异步任务的并发数GetMapping(path/demo4)publicCompletableFutureStringdemo4(){log.info(demo4 被调用当前线程{},Thread.currentThread().getName());returnCompletableFuture.completedFuture(demo4);}}三、应用场景与最佳实践1. 典型应用场景API限流保护后端服务不被突发流量打垮数据库连接控制限制对数据库的高并发访问第三方API调用防止超出第三方服务的配额限制资源密集型操作控制CPU/内存密集型操作的并发数2. 注意事项阻塞 vs 拒绝ConcurrencyLimit默认采用阻塞策略超出限制的请求会等待而非直接拒绝。如需快速失败可通过timeout参数设置超时时间。线程池关系并发限制是在应用层面的控制与底层的线程池无关。即使线程池有10个线程limit1也能确保同时只有一个请求执行业务逻辑。事务边界如果同时使用Transactional和ConcurrencyLimit需要注意注解的执行顺序。建议将ConcurrencyLimit放在外层。3. 与Resilience4j对比特性Spring 7.0内置Resilience4j并发限制✅ConcurrencyLimit✅ Bulkhead实现方式注解编程式注解编程式等待策略阻塞等待可配置(阻塞/快速失败)集成度与Spring生态无缝集成需额外依赖SpringBoot 4.0通过ConcurrencyLimit注解为开发者提供了一种简洁高效的并发控制方案声明式配置通过简单的注解即可实现方法级别的并发限制灵活的策略支持并发数、超时时间等参数的自定义编程式支持提供了ConcurrencyThrottleSupport和SyncTaskExecutor等API零侵入集成与Spring生态完美融合学习成本低通过合理使用并发限制特性我们可以有效提升应用的稳定性和资源利用率构建更加健壮的微服务系统。扩展阅读SpringBoot 4.0新特性失败重试Spring 7.0 Resilience模块官方文档并发控制与限流设计模式注本文基于Spring 7.0/SpringBoot 4.0预览版特性编写最终发布版本可能略有调整。