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

为Spring Integration动态URL的Http Outbound Gateway配置动态超时

Dynamic Timeouts for Spring Integration HTTP Outbound Gateway with Dynamic URLs

Question Context

I have an HTTP outbound gateway using dynamic URLs configured with fixed connection and read timeouts, like this:

<int-http:outbound-gateway request-channel="request" reply-channel="response" 
    url-expression="headers.serviceUrl" http-method="POST" 
    expected-response-type="java.lang.String" charset="UTF-8" 
    request-factory="httpOutboundRequestFactoryBean" 
    message-converters="messageConverterList" header-mapper="headerMapperBean"/>

<bean id="httpOutboundRequestFactoryBean" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
    <property name="readTimeout" value="5000"/>
    <property name="connectTimeout" value="1000"/>
</bean>

Is there a way to configure specific timeouts based on the URL defined in headers.serviceUrl? I've searched and found related questions, with one approach being to use a RestTemplate directly (creating a new instance each time with a request factory configured with URL-specific timeouts). But maybe Spring Integration has a built-in way to handle this? Thanks for the help!


Solution

While Spring Integration doesn't have a direct out-of-the-box feature for per-URL dynamic timeouts with the HTTP outbound gateway, you can implement this cleanly by combining a ThreadLocal to pass dynamic timeout values with a custom extension of HttpComponentsClientHttpRequestFactory. Here's how to do it step by step:

1. Create a ThreadLocal Holder for Dynamic Timeouts

First, make a class to hold a thread-local variable that stores the dynamic timeout value. We'll set this value in a service activator before the HTTP outbound gateway (you can replace the random timeout logic with your own URL-to-timeout mapping):

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import java.util.Random;

public class ThreadLocalTimeoutHolder {
    public static ThreadLocal<Integer> serviceTimeout = new ThreadLocal<>();
    private static final Logger LOGGER = LoggerFactory.getLogger(ThreadLocalTimeoutHolder.class);

    public Message<?> setTimeout(final Message<?> message){
        // Replace this with logic to map headers.serviceUrl to specific timeouts
        final int timeout = (new Random().nextInt(20 - 1 + 1) + 1)*1000;
        serviceTimeout.set(timeout);
        LOGGER.info("Set dynamic service timeout (thread-local): {}", timeout);
        return message;
    }
}

Add this service activator to your flow to inject the dynamic timeout before the gateway:

<int:service-activator input-channel="preRequestChannel" output-channel="request"
    ref="threadLocalTimeoutHolder" method="setTimeout"/>

<bean id="threadLocalTimeoutHolder" class="sample.ThreadLocalTimeoutHolder"/>

2. Extend HttpComponentsClientHttpRequestFactory

Next, extend the default request factory to override the mergeRequestConfig method. This is where we'll replace the default socket timeout (read timeout) with the value from our thread-local variable:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.apache.http.client.config.RequestConfig;

public class DynamicTimeoutRequestFactory extends HttpComponentsClientHttpRequestFactory {
    private RequestConfig requestConfig;
    private static final Logger LOGGER = LoggerFactory.getLogger(DynamicTimeoutRequestFactory.class);

    @Override
    protected RequestConfig createRequestConfig(final Object client) {
        this.requestConfig = super.createRequestConfig(client);
        return this.requestConfig;
    }

    @Override
    protected RequestConfig mergeRequestConfig(final RequestConfig clientConfig) {
        if (this.requestConfig == null) {
            return clientConfig;
        }

        final RequestConfig.Builder builder = RequestConfig.copy(clientConfig);
        // Preserve configured connect timeout
        final int connectTimeout = this.requestConfig.getConnectTimeout();
        if (connectTimeout >= 0) {
            builder.setConnectTimeout(connectTimeout);
        }
        // Preserve configured connection request timeout
        final int connectionRequestTimeout = this.requestConfig.getConnectionRequestTimeout();
        if (connectionRequestTimeout >= 0) {
            builder.setConnectionRequestTimeout(connectionRequestTimeout);
        }
        // Apply dynamic timeout from ThreadLocal
        final int socketTimeout = ThreadLocalTimeoutHolder.serviceTimeout.get();
        LOGGER.info("Applying dynamic service timeout: {}", socketTimeout);
        if (socketTimeout >= 0) {
            builder.setSocketTimeout(socketTimeout);
        }
        // Clear ThreadLocal to avoid memory leaks in thread pools
        ThreadLocalTimeoutHolder.serviceTimeout.remove();
        return builder.build();
    }
}

3. Update Spring Configuration

Finally, update your HTTP outbound gateway to use the custom request factory:

<int-http:outbound-gateway request-channel="request" reply-channel="response" 
    url-expression="headers.serviceUrl" http-method="POST" 
    expected-response-type="java.lang.String" charset="UTF-8" 
    request-factory="dynamicTimeoutRequestFactory" 
    message-converters="messageConverterList" header-mapper="headerMapperBean"/>

<bean id="dynamicTimeoutRequestFactory" class="sample.DynamicTimeoutRequestFactory">
    <property name="readTimeout" value="5000"/> <!-- Fallback timeout if no dynamic value is set -->
    <property name="connectTimeout" value="1000"/>
</bean>

Key Notes

  • Always clear the ThreadLocal variable after use to prevent memory leaks in thread pool environments.
  • Adjust the setTimeout method to map specific URLs (from message.getHeaders().get("serviceUrl")) to your predefined timeout values.
  • The configured readTimeout acts as a fallback if no dynamic timeout is provided for a URL.

内容的提问来源于stack exchange,提问作者gllambi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 23:29:13