如何在Spring AsyncRestTemplate中使用Apache CachingHttpAsyncClient?

时间:2017-06-14 08:14:01

标签: spring apache-httpcomponents asyncresttemplate

是否可以将CachingHttpAsyncClientAsyncRestTemplate一起使用? HttpComponentsAsyncClientHttpRequestFactory期望CloseableHttpAsyncClientCachingHttpAsyncClient不会延长它。

1 个答案:

答案 0 :(得分:0)

对于最高4.3.9和5.0.RC2的版本,这被称为问题SPR-15664 - 已在4.3.10和5.0.RC3中修复。唯一的解决方法是创建基于现有AsyncClientHttpRequestFactory的自定义HttpComponentsAsyncClientHttpRequestFactory实施:

// package required for HttpComponentsAsyncClientHttpRequest visibility
package org.springframework.http.client;

import java.io.IOException;
import java.net.URI;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.Configurable;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.cache.CacheConfig;
import org.apache.http.impl.client.cache.CachingHttpAsyncClient;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.protocol.HttpContext;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.HttpMethod;
import org.springframework.util.Assert;

// TODO add support for other CachingHttpAsyncClient otpions, e.g. HttpCacheStorage
public class HttpComponentsCachingAsyncClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory implements AsyncClientHttpRequestFactory, InitializingBean {

    private final CloseableHttpAsyncClient wrappedHttpAsyncClient;
    private final CachingHttpAsyncClient cachingHttpAsyncClient;

    public HttpComponentsCachingAsyncClientHttpRequestFactory() {
        this(HttpAsyncClients.createDefault(), CacheConfig.DEFAULT);
    }

    public HttpComponentsCachingAsyncClientHttpRequestFactory(final CacheConfig config) {
        this(HttpAsyncClients.createDefault(), config);
    }

    public HttpComponentsCachingAsyncClientHttpRequestFactory(final CloseableHttpAsyncClient client) {
        this(client, CacheConfig.DEFAULT);
    }

    public HttpComponentsCachingAsyncClientHttpRequestFactory(final CloseableHttpAsyncClient client, final CacheConfig config) {
        Assert.notNull(client, "HttpAsyncClient must not be null");
        wrappedHttpAsyncClient = client;
        cachingHttpAsyncClient = new CachingHttpAsyncClient(client, config);
    }

    @Override
    public void afterPropertiesSet() {
        startAsyncClient();
    }

    private void startAsyncClient() {
        if (!wrappedHttpAsyncClient.isRunning()) {
            wrappedHttpAsyncClient.start();
        }
    }

    @Override
    public ClientHttpRequest createRequest(final URI uri, final HttpMethod httpMethod) throws IOException {
        throw new IllegalStateException("Synchronous execution not supported");
    }

    @Override
    public AsyncClientHttpRequest createAsyncRequest(final URI uri, final HttpMethod httpMethod) throws IOException {
        startAsyncClient();
        final 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(cachingHttpAsyncClient);
            }
            if (config != null) {
                context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);
            }
        }
        return new HttpComponentsAsyncClientHttpRequest(cachingHttpAsyncClient, httpRequest, context);
    }

    @Override
    public void destroy() throws Exception {
        try {
            super.destroy();
        } finally {
            wrappedHttpAsyncClient.close();
        }
    }

}