动态 url http-outbound-gateway 的动态超时

Dynamic timeout for dynamic url http-outbound-gateway

我有一个 http-outbound-gateway,它使用动态 urls 连接和读取超时

<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>

是否可以根据headers.serviceUrl中定义的url配置特定超时?

我找了一圈,只找到了这个

一种解决方法是直接使用 RestTemplate 并每次创建一个 RestTemplate 实例并根据 url 动态设置 requestFactory(超时),但也许有一种内置的方法可以做到这一点spring 集成

提前致谢!

编辑:添加答案

我在 http-outbound-gateway 之前添加了这个服务激活器

public class ThreadLocalSample {

public static ThreadLocal<Integer> serviceTimeout = new ThreadLocal<>();

private static final Logger LOGGER = LoggerFactory.getLogger(ThreadLocalSample.class);

public Message<?> setTimeout(final Message<?> message){
    final int number = (new Random().nextInt(20 - 1 + 1) + 1)*1000;
    serviceTimeout.set(number);
    LOGGER.info("Service timeout thread local: "+number);

    return message;
}

扩展了 HttpComponentsClientHttpRequestFactory 并使用线程本地超时覆盖合并配置:

public class MyHttpConnectionFactory extends HttpComponentsClientHttpRequestFactory {

private RequestConfig requestConfig;

private static final Logger LOGGER = LoggerFactory.getLogger(MyHttpConnectionFactory.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) {  // nothing to merge
        return clientConfig;
    }

    final RequestConfig.Builder builder = RequestConfig.copy(clientConfig);
    final int connectTimeout = this.requestConfig.getConnectTimeout();
    if (connectTimeout >= 0) {
        builder.setConnectTimeout(connectTimeout);
    }
    final int connectionRequestTimeout = this.requestConfig.getConnectionRequestTimeout();
    if (connectionRequestTimeout >= 0) {
        builder.setConnectionRequestTimeout(connectionRequestTimeout);
    }
    final int socketTimeout = ThreadLocalSample.serviceTimeout.get();
    LOGGER.info("Service timeout: "+socketTimeout);
    if (socketTimeout >= 0) {
        builder.setSocketTimeout(socketTimeout);
    }
    return builder.build();
}

}

spring集成流程修改:

<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="sample.MyHttpConnectionFactory">
        <property name="readTimeout" value="5000"/>
        <property name="connectTimeout" value="1000"/>
</bean>

嗯,没有,我怀疑我们会在框架中对此事采取任何行动。 Spring 集成完全依赖于 ClientHttpRequestFactory 及其合约。因此,我们最多可以建议的是一些自定义的东西,扩展你的 HttpComponentsClientHttpRequestFactory.

如果我们查看这个工厂的源代码,我们会发现类似这样的内容:

public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
    HttpClient client = getHttpClient();

    HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri);
    postProcessHttpRequest(httpRequest);
    HttpContext context = createHttpContext(httpMethod, uri);
    if (context == null) {
        context = HttpClientContext.create();
    }

    // Request configuration not set in the context
    if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
        // Use request configuration given by the user, when available
        RequestConfig config = null;
        if (httpRequest instanceof Configurable) {
            config = ((Configurable) httpRequest).getConfig();
        }
        if (config == null) {
            config = createRequestConfig(client);
        }
        if (config != null) {
            context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);
        }
    }

因此,每次调用 createRequest() 时,它都会咨询 HttpContext and/or RequestConfig 之类的内容。

因此,作为满足您要求的解决方案,我建议处理您在提到的 <int-http:outbound-gateway> 之前填充的 ThreadLocal 并从该自定义 createHttpContext()createRequestConfig().