Spring @Retryable注解为何对未声明的异常尝试执行恢复逻辑?
这个问题其实是Spring Retry一个容易被忽略的默认行为细节,我来给你拆解清楚:
问题原因分析
你在@Retryable里只指定了retryFor = MyRetryableException.class,这确实意味着只有MyRetryableException会触发重试逻辑——这也是为什么抛出JustGiveUpException时,talkToSomething只被调用一次的原因。
但这里有个关键细节:Spring Retry的默认逻辑是,只要方法抛出的异常没有被明确排除,即使它不会触发重试,框架也会尝试寻找对应的@Recover恢复方法。
当你的方法抛出JustGiveUpException时,因为它不在retryFor列表里,所以不会重试,但框架还是会去扫描适配这个异常的@Recover方法。而你目前的@Recover方法只针对MyRetryableException,找不到匹配的恢复逻辑,就会抛出ExhaustedRetryException,并把原JustGiveUpException作为异常原因,同时给出“Cannot locate recovery method”的提示。
解决方案
根据你的需求(希望直接抛出JustGiveUpException,不触发任何恢复逻辑),最贴合的方案是给@Retryable添加exclude属性,明确排除不需要处理的异常:
方案1:排除指定异常
修改你的@Retryable注解,把JustGiveUpException加入排除列表:
@Retryable(retryFor = MyRetryableException.class, maxAttempts = 3, exclude = JustGiveUpException.class) public void doSomething(String s) throws JustGiveUpException { // 原方法逻辑不变 }
这样当方法抛出JustGiveUpException时,Spring Retry会直接将这个异常抛出,不会尝试执行任何重试或恢复流程。
方案2:添加对应异常的恢复方法(可选)
如果你后续需要对JustGiveUpException做自定义恢复处理,可以新增一个适配它的@Recover方法,比如:
@Recover public void handleGiveUpException(JustGiveUpException e, String s) { // 这里可以添加自定义处理逻辑,比如直接抛出原异常 throw e; }
内容来源于stack exchange

