我在我的一个库中使用 RestTemplate
作为我的 HttpClient
。我不确定我是否在多线程环境中正确使用它,因为我的库将在多线程环境中以非常重的负载使用,因此它必须非常快。
下面是我的 DataClient 类:
public class DataClient implements Client {
private RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory());
private ExecutorService executor = Executors.newFixedThreadPool(10);
// for synchronous call
@Override
public DataResponse executeSync(DataKey key) {
DataResponse dataResponse = null;
Future<DataResponse> future = null;
try {
future = executeAsync(key);
dataResponse = future.get(key.getTimeout(), TimeUnit.MILLISECONDS);
} catch (TimeoutException ex) {
dataResponse = new DataResponse(null, DataErrorEnum.TIMEOUT, DataStatusEnum.ERROR);
future.cancel(true);
} catch (Exception ex) {
dataResponse = new DataResponse(null, DataErrorEnum.CLIENT_ERROR, DataStatusEnum.ERROR);
}
return dataResponse;
}
//for asynchronous call
@Override
public Future<DataResponse> executeAsync(DataKey key) {
Future<DataResponse> future = null;
Task task = new Task(key, restTemplate);
future = executor.submit(task);
return future;
}
// does this looks right?
private ClientHttpRequestFactory clientHttpRequestFactory() {
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
// setting 2000 ms as the default timeout for each Http Request
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(2000).setConnectTimeout(2000)
.setSocketTimeout(2000).setStaleConnectionCheckEnabled(false).build();
SocketConfig socketConfig = SocketConfig.custom().setSoKeepAlive(true).setTcpNoDelay(true).build();
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
poolingHttpClientConnectionManager.setMaxTotal(800);
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(700);
CloseableHttpClient httpClientBuilder = HttpClientBuilder.create()
.setConnectionManager(poolingHttpClientConnectionManager).setDefaultRequestConfig(requestConfig)
.setDefaultSocketConfig(socketConfig).build();
requestFactory.setHttpClient(httpClientBuilder);
return requestFactory;
}
}
将执行实际任务的简单类:
public class Task implements Callable<DataResponse> {
private final DataKey key;
private final RestTemplate restTemplate;
public Task(DataKey key, RestTemplate restTemplate) {
this.key = key;
this.restTemplate = restTemplate;
}
@Override
public DataResponse call() {
DataResponse dataResponse = null;
String response = null;
try {
String url = createURL();
response = restTemplate.getForObject(url, String.class);
dataResponse = new DataResponse(response, DataErrorEnum.OK, DataStatusEnum.SUCCESS);
} catch (RestClientException ex) {
dataResponse = new DataResponse(null, DataErrorEnum.SERVER_DOWN, DataStatusEnum.ERROR);
} catch (Exception ex) {
dataResponse = new DataResponse(null, DataErrorEnum.CLIENT_ERROR, DataStatusEnum.ERROR);
}
return dataResponse;
}
}
下面是我的工厂,我用它来创建 DataClient 的单个实例,这意味着它也将有 RestTemplate
的单个实例。
public class DataClientFactory {
private DataClientFactory() {}
private static class ClientHolder {
private static final DataClient INSTANCE = new DataClient();
}
public static Client getInstance() {
return ClientHolder.INSTANCE;
}
}
这就是我调用以获取数据的方式:
DataResponse response = DataClientFactory.getInstance().executeSync(dataKey);
现在我的问题是 - 我不确定我是否将 RestTemplate
与 HttpComponentsClientHttpRequestFactory
一起正确使用。我是否需要 PoolingHttpClientConnectionManager
以及 RestTemplate
?
我的主要目标是在多线程环境中高效地使用 RestTemplate
。由于我的库将在非常重的负载下使用,因此它必须非常快。在重负载下,我看到很多 TIME_WAIT 连接,所以我添加了 clientHttpRequestFactory()
方法以与 RestTemplate
一起使用。
最佳答案
RestTemplate
是 thread safe在 Spring 。因此,您可能想要做的是在您的应用程序中只创建一个 RestTemplate
实例,并在多个线程之间共享它。这当然是假设您将对所有人使用相同的 HTTP 属性(如超时、设置 Activity 等)。如果您需要更改连接属性,您可以在 RestTemplate
对象的应用启动时创建一个池,并使用它将 RestTemplate 实例注入(inject)调用者类。
关于java - 如何在多线程应用程序中高效使用 RestTemplate?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31151990/