0

我正在 Spring MVC 整体应用程序中编写自定义 RestService(wrapper of Apache Http Client 4.5.10) 和 RestServiceAsync(wrapper of Apache httpasyncclient 4.1.4)。

下面是我的IRestService

public interface IRestService {

    public <T> T request(HttpUriRequest request, final ResponseParser<T> responseParser);

    public <T> Optional<T> request(final HttpMethod method);

    public <T> T call(HttpUriRequest request, ResponseHandler<T> responseHandler);

    default <T> Optional<T> get() {
        return request(HttpMethod.GET);
    }

    public default <T> Optional<T> get(String URL) {
        return get(URL, Collections.EMPTY_MAP, ResponseParsers.STRING);
    }

    public default <T> Optional<T> get(String URL, boolean isAsync) {
        return get(URL, Collections.EMPTY_MAP, ResponseParsers.STRING);
    }

    public default <T> Optional<T> get(String URL, Map params) {
        return get(URL, params, ResponseParsers.STRING);
    }

    public default <T> Optional<T> get(String url, Map<String, String> params, ResponseParser<T> responseParser) {
        return request(url, params, HttpMethod.GET, responseParser);
    }

    public default <T> Optional<T> get(String URL, ResponseParser<T> responseParser) {
        return request(URL, Collections.EMPTY_MAP, HttpMethod.GET, responseParser);
    }

    public default <T> Optional<T> request(String url, Map params, HttpMethod httpMethod, ResponseParser<T> responseParser) {
        return request(url, null, params, httpMethod, responseParser);
    }

    public  <T> Optional<T> request(String url, HttpEntity entity, Map params, HttpMethod httpMethod, ResponseParser<T> responseParser);

    HttpResponse execute(HttpUriRequest request, Closeable httpClient) ;
}

下面是我的RestServiceBase

public abstract class RestServiceBase implements IRestService{

    @Override
    public <T> Optional<T> request(HttpMethod method) {
        return Optional.empty();
    }

    @Override
    public <T> Optional<T> request(String url, HttpEntity entity, Map params, HttpMethod httpMethod, ResponseParser<T> responseParser) {
        T respose = null;
        try {
            final HttpUriRequest httpUriRequest = buildHttpUriRequest(httpMethod, url, entity, params);

            respose = (T) request(httpUriRequest, responseParser);
        } catch (HttpException | URISyntaxException e) {
            e.printStackTrace();
        }
        return Optional.ofNullable(respose);
    }

    public <T> T request(HttpUriRequest request, final ResponseParser<T> responseParser) {
        return call(request, new BaseResponseHandler<>(entity -> {
            // Gets the content as a string
            String content = entity != null ? EntityUtils.toString(entity, "UTF-8") : null;
            // Parses the response
            return responseParser.parse(content);
        }));
    }


    private HttpUriRequest buildHttpUriRequest(HttpMethod httpMethod, String url, HttpEntity entity,
                                               Map<String, String> params) throws HttpException, URISyntaxException {
        URI uri = buildURI(url, params);
        final RequestBuilder requestBuilder = resolveRequestBuilder(httpMethod,uri);
        Optional.ofNullable(entity).ifPresent(requestBuilder::setEntity);
        return requestBuilder.build();
    }

    private URI buildURI(String url, Map<String, String> params) throws URISyntaxException {
        URIBuilder uriBuilder = new URIBuilder(url);
        Optional.ofNullable(params.entrySet())
                .ifPresent(map -> map.forEach(e -> uriBuilder.setParameter(e.getKey(), e.getValue())));

        return uriBuilder.build();
    }


    private RequestBuilder resolveRequestBuilder(HttpMethod method, URI uri) throws HttpException {
        switch (method) {
            case GET:
                return RequestBuilder.get().setUri(uri);

            case PUT:
                return RequestBuilder.put().setUri(uri);

            case POST:
                return RequestBuilder.post().setUri(uri);

            case DELETE:
                return RequestBuilder.delete().setUri(uri);
            default:
                throw new HttpException("Unsupported HttpMethod " + method);
        }

    }
}

下面是我的RestService(它使用同步版本的 Apache http 客户端)

@Service
public class RestService extends RestServiceBase{

     @Autowired
    HttpClientFactory           httpClientFactory;

    public HttpResponse execute(HttpUriRequest request, Closeable httpClient) {
        if(! (httpClient instanceof CloseableHttpClient))
            throw new RuntimeException("UnSupported HttpClient Exception");
        try {
            CloseableHttpClient closeableHttpClient = (CloseableHttpClient) httpClient;
            return closeableHttpClient.execute(request);
        } catch (IOException e) {
            throw new RuntimeException();
        }
    }

    private CloseableHttpClient getHttpClient() {
        ApacheHttpClient apacheHttpClient = (ApacheHttpClient) httpClientFactory.getApacheHttpClient();
        return (CloseableHttpClient) apacheHttpClient.getHttpClient();
    }

    public <T> T call(HttpUriRequest request, ResponseHandler<T> responseHandler) {
        try {
            try (CloseableHttpClient httpClient = getHttpClient()) {
                HttpResponse response = execute(request, httpClient);
                // Entity response
                HttpEntity entity = response.getEntity();
                try {
                    return responseHandler.handleResponse(request, response, entity);
                } finally {
                    EntityUtils.consume(entity);
                }
            }
        } catch (IOException e) {
            throw new ClientGeneralException(request, e);
        } finally {
            ((HttpRequestBase) request).releaseConnection();
        }
    }

}

下面是我的RestService(它使用Apache http 客户端的异步版本)

@Service
public class RestServiceAsync extends RestServiceBase{

     @Autowired
    HttpClientFactory           httpClientFactory;

    public HttpResponse execute(HttpUriRequest request, Closeable httpClient) {
        if(! (httpClient instanceof CloseableHttpAsyncClient))
            throw new RuntimeException("UnSupported HttpClient Exception");
        try {
            CloseableHttpAsyncClient closeableHttpClient = (CloseableHttpAsyncClient) httpClient;
            Future<HttpResponse> future = closeableHttpClient.execute(request, null);
            HttpResponse response = future.get();
            return response;
            //return (HttpResponse) closeableHttpClient.execute(request,null);
        } catch (InterruptedException | ExecutionException e) {
            request.abort();
            throw new RuntimeException();
        }
    }

    private CloseableHttpAsyncClient getHttpClient() {
        ApacheAsyncClient apacheAsyncClient = (ApacheAsyncClient) httpClientFactory.getApacheAsyncHttpClient();
        return (CloseableHttpClient) apacheAsyncClient.getHttpClient();
    }

    public <T> T call(HttpUriRequest request, ResponseHandler<T> responseHandler) {
        try {
            try (CloseableHttpAsyncClient httpClient = getHttpClient()) {
                HttpResponse response = execute(request, httpClient);
                // Entity response
                HttpEntity entity = response.getEntity();
                try {
                    return responseHandler.handleResponse(request, response, entity);
                } finally {
                    EntityUtils.consume(entity);
                }
            }
        } catch (IOException e) {
            throw new ClientGeneralException(request, e);
        } finally {
            ((HttpRequestBase) request).releaseConnection();
        }
    }
}

下面是我的示例用例RestServiceAsync

@Service
ReportsService(){

    @Autowired
    @Qualifier("restServiceAsync")
    RestService restService;

    public getReport(){
            restService.get("http://localhost/reports");
    }
}

我想引入响应读取timeout,以便执行RestServiceAsync.execute方法的主线程不会等待超过不同用例所需的时间。以下是我这样做的方法

1 . 在和 do中引入一个私有timeout变量并使用 setter 方法。这种方法不可行,因为单例 bean 设置变量会反映应用程序的所有用户RestServiceAsyncHttpResponse response = future.get(timeout, TimeUnit.Seconds);RestServiceAsynctimeout

2 . timeout从方法调用中作为参数发送为restService.get("http://localhost/reports",30); 这可行,但我必须更新IRestService.

我想知道是否有一种替代的有效方法可以引入timeout,而不必触及所有方法,IRestService而只需在RestServiceAsync

PS:ApacheAsyncClient 使用PoolingNHttpClientConnectionManager和 ApacheHttpClient 使用PoolingHttpClientConnectionManager

4

0 回答 0