Spring Boot Retry监听器异常触发问题咨询(未配置却调用onError、捕获非指定异常)
Spring Boot Retry监听器异常触发问题咨询(未配置却调用onError、捕获非指定异常)
你好,针对你遇到的Spring Boot Retry监听器的两个问题,我来帮你梳理下原因和可行的解决方案:
问题1:未配置监听器的@Retryable方法也会触发所有RetryListener的onError
你提到即使@Retryable注解没指定listeners参数,容器里所有的RetryListener Bean都会被触发,这其实是Spring Retry的默认全局监听器机制导致的:
Spring Retry会自动把所有注册为Spring Bean的RetryListener(比如你用@Component标记的TestServiceRetryListener)当作全局监听器,默认应用到所有标注了@Retryable的方法上。这就是为什么你需要给每个方法都指定listeners={"defaultRetryListener"}来规避其他监听器的原因。
解决方案
你可以通过以下几种方式修改这个行为:
- 关闭全局监听器自动注册:如果你的Spring Boot版本支持(一般2.4+版本),可以在配置文件中添加:
这样只有显式在spring.retry.listeners.default-enabled=false@Retryable的listeners参数里指定的监听器才会被触发,全局Bean不会自动生效。 - 避免监听器成为全局Bean:去掉
TestServiceRetryListener上的@Component注解,改为在需要使用的地方手动注入,或者通过@Bean的方式只给特定的RetryTemplate配置该监听器。 - 自定义RetryTemplate:创建自定义的RetryTemplate Bean,只配置你需要的默认监听器,然后在
@Retryable中指定template参数来使用这个自定义模板。
问题2:监听器onError触发了非retryFor指定的异常
这个其实是Spring Retry的设计逻辑:RetryListener的onError方法是在每次方法抛出异常时都会被调用,不管这个异常是否在retryFor的范围内。因为框架的执行顺序是:
- 执行目标方法抛出异常
- 调用监听器的
onError方法 - 判断异常是否符合
retryFor/noRetryFor的规则,决定是否执行重试
所以即使异常不在retryFor列表里,只要方法抛出了异常,onError就会被触发。
解决方案
如果你只想处理retryFor指定的异常,可以在监听器的onError方法里手动判断异常类型:
@Override public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { // 获取@Retryable注解的retryFor属性 Retryable retryable = context.getAttribute(Retryable.class); if (retryable != null) { Class<? extends Throwable>[] retryFor = retryable.retryFor(); // 判断当前异常是否属于retryFor指定的类型 for (Class<? extends Throwable> clazz : retryFor) { if (clazz.isInstance(throwable)) { // 执行你需要的逻辑 log.info("处理符合重试条件的异常: {}", throwable.getMessage()); break; } } } }
或者你也可以直接在代码中判断异常实例是否是目标类型,比如:
if (throwable instanceof TestReasonAException) { // 执行逻辑 }
附上你提供的监听器代码参考:
package com.example.springbootretrytest.service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.retry.RetryCallback; import org.springframework.retry.RetryContext; import org.springframework.retry.RetryListener; import org.springframework.stereotype.Component; @Component("testServiceRetryListener") public class TestServiceRetryListener implements RetryListener { @Override public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { // do something } }
备注:内容来源于stack exchange,提问作者00schmidt
相关产品推荐
相关产品推荐

