You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Retry:如何在RetryListener的onError中访问并修改失败方法参数?

解决Spring Retry监听器无法访问方法参数的问题

你的问题核心在于Spring Retry的默认RetryListener没法直接拿到方法调用时的参数,而且监听器本身主要是做事件监听,没法直接修改重试时的参数。这里给你两种实用的解决方案,其中第一种更推荐,适配你的场景:


方案一:使用@Recover恢复方法(推荐)

这种方式不需要自定义监听器,直接利用Spring Retry提供的@Recover注解处理异常恢复逻辑,能直接获取原方法的所有参数,代码简洁且符合框架设计意图。

修改后的代码示例:

首先假设你有一个负责重新登录的LoginService(需要你自己实现具体的登录逻辑):

@Service
public class LoginService {
    public String login(String username) {
        // 这里实现调用外部系统登录、返回新sessionToken的逻辑
        return "new-valid-session-token";
    }
}

然后调整你的EmployeeService,添加@Recover方法:

@Service
public class EmployeeService {

    @Autowired
    private LoginService loginService;

    // 指定仅对UnknownSessionException重试,最多重试1次(总共调用2次)
    @Retryable(retryFor = UnknownSessionException.class, maxAttempts = 2)
    public void createEmployee(Session session, String employeeName) throws UnknownSessionException {
        // 原方法逻辑:调用外部系统,可能抛出UnknownSessionException
        externalSystemClient.createEmployee(session.getSessionToken(), employeeName);
    }

    // 当createEmployee抛出UnknownSessionException时,自动触发此方法
    @Recover
    public void recoverSessionError(UnknownSessionException ex, Session session, String employeeName) {
        // 1. 用原Session的用户名重新登录,获取新的sessionToken
        String newSessionToken = loginService.login(session.getUsername());
        
        // 2. 创建新Session对象(因为你的Session是@Value不可变类,无法修改原对象的token)
        Session newValidSession = new Session(session.getUsername(), newSessionToken);
        
        // 3. 带着新Session重新调用原方法
        createEmployee(newValidSession, employeeName);
    }
}

方案二:通过RetryContext存储参数(适合必须用监听器的场景)

如果你一定要用自定义监听器,需要在原方法里把参数存入RetryContext,这样监听器就能在onError中拿到参数。不过要注意:监听器只能监听异常,没法直接修改原重试逻辑的参数,所以需要手动调用方法重试,还要自己控制重试次数。

修改后的代码示例:

1. 在EmployeeService中把参数存入RetryContext

@Service
public class EmployeeService {

    @Retryable(listeners = "employeeRetryListener", retryFor = UnknownSessionException.class)
    public void createEmployee(Session session, String employeeName) throws UnknownSessionException {
        // 将参数存入RetryContext
        RetryContext context = RetrySynchronizationManager.getContext();
        if (context != null) {
            context.setAttribute("currentSession", session);
            context.setAttribute("employeeName", employeeName);
        }
        
        // 原方法逻辑
        externalSystemClient.createEmployee(session.getSessionToken(), employeeName);
    }
}

2. 修改自定义监听器获取并处理参数

@Component
public class EmployeeRetryListener extends RetryListenerSupport {

    @Autowired
    private LoginService loginService;
    
    @Autowired
    private EmployeeService employeeService;

    @Override
    public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
        if (throwable instanceof UnknownSessionException) {
            // 从RetryContext中取出参数
            Session oldSession = (Session) context.getAttribute("currentSession");
            String employeeName = (String) context.getAttribute("employeeName");
            
            if (oldSession != null && employeeName != null) {
                // 重新登录获取新token
                String newToken = loginService.login(oldSession.getUsername());
                Session newSession = new Session(oldSession.getUsername(), newToken);
                
                // 手动控制重试次数,避免和@Retryable配置冲突
                if (context.getRetryCount() < context.getRetryPolicy().getMaxAttempts()) {
                    try {
                        employeeService.createEmployee(newSession, employeeName);
                    } catch (UnknownSessionException e) {
                        throw new RuntimeException("重试登录后仍无法创建员工", e);
                    }
                }
            }
        }
        super.onError(context, callback, throwable);
    }
}

额外提示:关于不可变的Session类

你的Session是@Value注解的不可变类(final字段、无setter),所以无法直接修改原对象的sessionToken,必须创建新的Session实例来传递有效token,两种方案都考虑到了这一点。

内容的提问来源于stack exchange,提问作者Vincent B.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:00:11