У меня есть библиотека, которая используется клиентом, и они передают объект DataRequest
, который имеет userid
, timeout
и некоторые другие поля в нем. Теперь я использую этот объект DataRequest
для создания URL-адреса, а затем я делаю HTTP-вызов с помощью RestTemplate
, и моя служба возвращает ответ JSON, который я использую для создания объекта DataResponse
и возвращает этот объект DataResponse
назад к ним.
Ниже мой класс DataClient
, используемый клиентом, передавая ему объект DataRequest
. Я использую значение тайм-аута, переданное клиентом в DataRequest
, чтобы пропустить запрос, если он занимает слишком много времени в методе getSyncData
.
public class DataClient implements Client {
private final RestTemplate restTemplate = new RestTemplate();
private final ExecutorService service = Executors.newFixedThreadPool(10);
// this constructor will be called only once through my factory
// so initializing here
public DataClient() {
try {
restTemplate.setRequestFactory(clientHttpRequestFactory());
} catch (Exception ex) {
// log exception
}
}
@Override
public DataResponse getSyncData(DataRequest key) {
DataResponse response = null;
Future<DataResponse> responseFuture = null;
try {
responseFuture = getAsyncData(key);
response = responseFuture.get(key.getTimeout(), key.getTimeoutUnit());
} catch (TimeoutException ex) {
response = new DataResponse(DataErrorEnum.CLIENT_TIMEOUT, DataStatusEnum.ERROR);
responseFuture.cancel(true);
// logging exception here
}
return response;
}
@Override
public Future<DataResponse> getAsyncData(DataRequest key) {
DataFetcherTask task = new DataFetcherTask(key, restTemplate);
Future<DataResponse> future = service.submit(task);
return future;
}
// how to set socket timeout value by using `key.getSocketTimeout()` instead of using hard coded 400
private ClientHttpRequestFactory clientHttpRequestFactory() {
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
RequestConfig requestConfig =
RequestConfig.custom().setConnectionRequestTimeout(400).setConnectTimeout(400)
.setSocketTimeout(400).setStaleConnectionCheckEnabled(false).build();
SocketConfig socketConfig =
SocketConfig.custom().setSoKeepAlive(true).setTcpNoDelay(true).build();
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager =
new PoolingHttpClientConnectionManager();
poolingHttpClientConnectionManager.setMaxTotal(300);
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(200);
CloseableHttpClient httpClientBuilder =
HttpClientBuilder.create().setConnectionManager(poolingHttpClientConnectionManager)
.setDefaultRequestConfig(requestConfig).setDefaultSocketConfig(socketConfig).build();
requestFactory.setHttpClient(httpClientBuilder);
return requestFactory;
}
}
DataFetcherTask
класс:
public class DataFetcherTask implements Callable<DataResponse> {
private final DataRequest key;
private final RestTemplate restTemplate;
public DataFetcherTask(DataRequest key, RestTemplate restTemplate) {
this.key = key;
this.restTemplate = restTemplate;
}
@Override
public DataResponse call() throws Exception {
// In a nutshell below is what I am doing here.
// 1. Make an url using DataRequest key.
// 2. And then execute the url RestTemplate.
// 3. Make a DataResponse object and return it.
}
}
Клиент в нашей компании будет использовать мою библиотеку, как показано ниже, используя мой factory в своей базе кода -
// if they are calling `getSyncData()` method
DataResponse response = DataClientFactory.getInstance().getSyncData(key);
// and if they want to call `getAsyncData()` method
Future<DataResponse> response = DataClientFactory.getInstance().getAsyncData(key);
Я реализую sync call as async + waiting
, так как я хочу дросселировать их количеством потоков, иначе они могут бомбить нашу службу без какого-либо контроля.
Проблема: -
Я собираюсь добавить еще одну переменную timeout с именем socket timeout
в мой класс DataRequest
, и я хочу использовать это значение переменной (key.getSocketTimeout())
в моем методе clientHttpRequestFactory()
вместо использования жесткого кодированного значения 400. Каков наилучший и эффективный способ сделать это?
Сейчас я использую Inversion of Control
и передаю RestTemplate
в конструкторе для совместного использования RestTemplate
между всеми объектами моей задачи. Теперь я запутался, как использовать значение key.getSocketTimeout()
в моем методе clientHttpRequestFactory()
. Я думаю, что в основном это вопрос дизайна о том, как эффективно использовать RestTemplate
здесь, чтобы я мог использовать значение key.getSocketTimeout()
в моем методе clientHttpRequestFactory()
.
Я упростил код, чтобы идея поняла, что я пытаюсь сделать, и я нахожусь на Java 7. Использование ThreadLocal
- единственный вариант, который у меня есть или есть лучший и оптимизированный способ?