Как использовать Apache CachingHttpAsyncClient с Spring AsyncRestTemplate?

Можно ли использовать CachingHttpAsyncClient с AsyncRestTemplate? HttpComponentsAsyncClientHttpRequestFactory ожидает CloseableHttpAsyncClient, но CachingHttpAsyncClient не расширяет его.


person sfussenegger    schedule 14.06.2017    source источник
comment
Я разместил это как продолжение stackoverflow.com/questions/43623608.   -  person sfussenegger    schedule 14.06.2017


Ответы (1)


Это известно как проблема SPR-15664 для версий до 4.3.9 и 5.0. RC2 — исправлено в 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();
        }
    }

}
person sfussenegger    schedule 14.06.2017