Spring 7.0 三大王炸注解來襲
環境:SpringBoot3.4.2
1. 簡介
在Spring Boot開發中,重試機制用于應對網絡波動、服務不可用等異常,通過自動重試提升系統健壯性;接口并發控制則防止過多請求導致性能下降。
重試與接口并發控制功能往往需借助第三方庫或手動實現。例如,重試機制通常通過引入spring-retry包,利用其 @Retryable 注解便捷配置重試次數、退避策略等,避免在業務代碼中硬編碼循環邏輯;而接口并發控制則可能依賴Guava RateLimiter實現單機限流,或結合Redis等分布式鎖工具(如Redisson)保障多實例環境下的并發安全。部分場景下,開發者也會通過AOP自定義注解實現重試或并發攔截,但需額外編寫切面邏輯,增加了維護成本。
自 Spring 7.x 版本起,框架原生集成了重試與接口并發控制功能,其中重試機制支持靈活的退避策略與異常匹配配置,而并發控制目前僅提供單機版限流能力,暫未涵蓋分布式場景下的集群限流支持。同時還提供了 @ImportHttpServices 注解簡化了聲明書Http Client的注冊方式。
2.實戰案例
目前 Spring Framework 7.0 尚未發布正式版本(尚未進入 RELASE 階段,當前仍處于快照版本(SNAPSHOT)開發階段),正式版本將于2025-11-13發布。我們需要進行如下配置:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.0-SNAPSHOT</version>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>接下來,還需要開啟功能
@SpringBootApplication
@EnableResilientMethods
public class Application {}接下來,我們詳細介紹這2個實用的功能。
2.1 重試機制@Retryable
@Retryable 是一種通用注解,用于指定單個方法(在方法級別聲明注解)或給定類層次結構中所有代理調用方法(在類型級別聲明注解)的重試特性。
@Retryable
public void sendMail() {
System.err.printf("%d - 發送郵件...", DateTimeFormatter.ofPattern("mm:ss").format(LocalDateTime.now())) ;
try {TimeUnit.SECONDS.sleep(1) ;} catch (InterruptedException e) {}
System.err.println(1 / 0) ;
}默認情況下,方法調用將重試拋出的任何異常:初始失敗后最多重試 3 次,兩次重試之間的延遲時間為 1 秒。
如有必要,可對每種方法進行專門調整,例如,縮小重試的例外情況范圍:
@Retryable(EmailException.class)
public void sendMail() {
// ...
}當方法執行拋出了EmailException異常,才會進行重試。
或者進行 5 次重試,并采用指數退避策略,但有一定的抖動:
@Retryable(maxAttempts = 2, delay = 100,
jitter = 10, multiplier = 2, maxDelay = 1000)
public void sendMail() {
// ...
}該示例運行結果
圖片
重試次數完了以后才拋出異常。
最后但并非最不重要的一點是,@Retryable 還適用于具有反應式返回類型的反應式方法,為管道裝飾了 Reactor 的重試功能:
@Retryable(maxAttempts = 5, delay = 100, jitter = 10,
multiplier = 2, maxDelay = 1000)
public Mono<Void> sendMail() {
// ...
return Mono.from(...) ;
}2.2 并發控制@ConcurrencyLimit
@ConcurrencyLimit 是一種注解,用于指定單個方法(在方法級別聲明注解)或給定類層次結構中所有代理調用方法(在類型級別聲明注解)的并發限制。
@ConcurrencyLimit(1)
public void callPhone() {
System.err.printf("%s - %s - 撥打電話...%n", Thread.currentThread().getName(),
DateTimeFormatter.ofPattern("mm:ss:SSS").format(LocalDateTime.now())) ;
try {TimeUnit.SECONDS.sleep(3) ;} catch (InterruptedException e) {}
}這里并發數設置為1,當有請求在處理,那么其它的請求則進入等待狀態。這樣做的目的是防止目標資源同時被太多線程訪問,效果類似于線程池或連接池的池大小限制,如果達到限制,就會阻止訪問。
這種限制對虛擬線程特別有用,因為虛擬線程通常沒有線程池限制。對于異步任務,可以在 SimpleAsyncTaskExecutor 上進行限制。對于同步調用,該注解通過 ConcurrencyThrottleInterceptor 提供了等效的行為。
圖片
2.3 自動注冊HttpClient
通過簡單地聲明接口,Spring 6 可以更輕松地定義 HTTP 客戶端,這與 Feign 的工作原理類似,如下示例:
public interface UserClient {
@GetExchange("/users")
List<User> getUsers();
@GetExchange("/users/{id}")
User getUserById(@PathVariable Long id);
}接下來,我們還需要進行如下的代理配置:
@Configuration
public class HttpClientConfiguration {
@Bean
RestClient.Builder restClient() {
return RestClient.builder();
}
@Bean
UserClient userHttpClient(RestClient.Builder builder) {
RestClient restClient = builder
.baseUrl("http://localhost:8081")
.build();
HttpServiceProxyFactory factory = HttpServiceProxyFactory
.builderFor(RestClientAdapter.create(restClient))
.build();
return factory.createClient(UserClient.class);
}
}如上配置后,我們就可以在其它的Bean中注入UserClient進行遠程接口調用了。
從 Spring Framework 7(Spring Boot 4)開始,你可以使用強大的 @ImportHttpServices 注解讓 Spring 自動掃描和注冊你的聲明式接口,從而進一步簡化工作,如下示例:
@Configuration
@ImportHttpServices(
group = "users",
basePackages = "com.pack.client"
)
public class HttpClientConfiguration {
@Bean
RestClient.Builder restClient() {
return RestClient.builder();
}
}通過如上的配置,Spring 會自動檢測并使用組和基礎包注冊它,如下示例:
@RestController
@RequestMapping("/api")
public class ApiController {
private final UserClient userClient ;
public ApiController(UserClient userClient) {
this.userClient = userClient ;
}
@GetMapping("/users")
public List<User> query() {
return this.userClient.getUsers() ;
}
}

































