Spring Integration:区分连接失败与错误响应码,仅重试连接失败
区分连接失败与HTTP错误码,仅对连接失败应用重试
问题的核心在于默认的SimpleRetryPolicy会对所有运行时异常进行重试,而连接失败抛出的ResourceAccessException和HTTP错误码抛出的RestClientResponseException都属于运行时异常,所以才会被一起重试。我们需要通过自定义重试策略来区分这两类异常,只对连接相关的异常触发重试逻辑。
步骤1:识别异常类型
首先明确两种场景对应的异常:
- 连接失败:通常会抛出
ResourceAccessException,其根源(getCause())一般是ConnectException(无法建立连接)或SocketTimeoutException(连接超时)。 - HTTP错误码(如400、500):会抛出
RestClientResponseException的子类,比如HttpClientErrorException(4xx)或HttpServerErrorException(5xx)。
步骤2:自定义重试策略
我们可以使用ExceptionClassifierRetryPolicy来实现异常分类,针对不同异常类型应用不同的重试规则:
@Bean("retryAdvice") public RequestHandlerRetryAdvice maspRetryAdvice() { RequestHandlerRetryAdvice retryAdvice = new RequestHandlerRetryAdvice(); RetryTemplate retryTemplate = new RetryTemplate(); // 配置退避策略(和你原来的逻辑一致) FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy(); backOffPolicy.setBackOffPeriod(interval); retryTemplate.setBackOffPolicy(backOffPolicy); // 创建分类重试策略 ExceptionClassifierRetryPolicy classifierRetryPolicy = new ExceptionClassifierRetryPolicy(); // 1. 连接失败时的重试策略:允许重试nRetry次 SimpleRetryPolicy connectionRetryPolicy = new SimpleRetryPolicy(); connectionRetryPolicy.setMaxAttempts(nRetry); // 2. HTTP错误码时的策略:不重试(仅执行1次) SimpleRetryPolicy noRetryPolicy = new SimpleRetryPolicy(); noRetryPolicy.setMaxAttempts(1); // 配置异常分类逻辑 classifierRetryPolicy.setExceptionClassifier(throwable -> { // 判断是否是连接相关异常 if (throwable instanceof ResourceAccessException) { Throwable rootCause = throwable.getCause(); if (rootCause instanceof ConnectException || rootCause instanceof SocketTimeoutException) { return connectionRetryPolicy; } } // 判断是否是HTTP响应错误异常 if (throwable instanceof RestClientResponseException) { return noRetryPolicy; } // 其他异常默认不重试(可根据需求调整) return noRetryPolicy; }); retryTemplate.setRetryPolicy(classifierRetryPolicy); // 恢复回调逻辑(保持你原来的配置) ErrorMessageSendingRecoverer recover = new ErrorMessageSendingRecoverer(aggregatorChannel()); retryAdvice.setRecoveryCallback(recover); retryAdvice.setRetryTemplate(retryTemplate); return retryAdvice; }
替代方案:使用SimpleRetryPolicy的异常映射
如果你不需要太精细的异常根源判断,也可以直接通过SimpleRetryPolicy的retryableExceptions来配置:
@Bean("retryAdvice") public RequestHandlerRetryAdvice maspRetryAdvice() { RequestHandlerRetryAdvice retryAdvice = new RequestHandlerRetryAdvice(); RetryTemplate retryTemplate = new RetryTemplate(); FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy(); backOffPolicy.setBackOffPeriod(interval); retryTemplate.setBackOffPolicy(backOffPolicy); SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(); Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>(); // 允许重试连接相关异常 exceptionMap.put(ResourceAccessException.class, true); // 禁止重试HTTP响应错误异常 exceptionMap.put(RestClientResponseException.class, false); retryPolicy.setRetryableExceptions(exceptionMap); retryPolicy.setMaxAttempts(nRetry); retryTemplate.setRetryPolicy(retryPolicy); ErrorMessageSendingRecoverer recover = new ErrorMessageSendingRecoverer(aggregatorChannel()); retryAdvice.setRecoveryCallback(recover); retryAdvice.setRetryTemplate(retryTemplate); return retryAdvice; }
关键说明
- 第一种方案更灵活,可以深入判断异常的根源,避免误重试其他类型的
ResourceAccessException(比如读取响应超时但连接已建立的情况)。 - 确保你的
Http.outboundGateway配置会正确抛出HTTP错误码异常:默认情况下,DefaultResponseErrorHandler会在非2xx状态码时抛出RestClientResponseException,如果自定义了errorHandler,需要保证异常被正确抛出。
内容的提问来源于stack exchange,提问作者Ramy Ahmed
相关产品推荐
相关产品推荐

