我正在 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 设置变量会反映应用程序的所有用户RestServiceAsync
HttpResponse response = future.get(timeout, TimeUnit.Seconds);
RestServiceAsync
timeout
2 . timeout
从方法调用中作为参数发送为restService.get("http://localhost/reports",30)
; 这可行,但我必须更新IRestService
.
我想知道是否有一种替代的有效方法可以引入timeout
,而不必触及所有方法,IRestService
而只需在RestServiceAsync
PS:ApacheAsyncClient 使用PoolingNHttpClientConnectionManager
和 ApacheHttpClient 使用PoolingHttpClientConnectionManager