我有一个图书馆,客户正在使用,他们正在通过 DataRequest
具有 userid
, timeout
还有其他一些领域。现在我用这个 DataRequest
对象创建一个url,然后使用 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 {
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.
}
}
我们公司内的客户将使用我的库,如下所示,在他们的代码库中使用我的工厂-
// if they are calling getSyncData()
method
DataResponse response = DataClientFactory.getInstance().getSyncData(key);
// and if they want to call getAsyncData()
method
Future response = DataClientFactory.getInstance().getAsyncData(key);
我正在实施 `sync call as async + waiting` 因为我想用线程的数量来限制它们,否则它们会在没有任何控制的情况下轰炸我们的服务。
问题statement:-
我将添加另一个名为 `socket timeout` 在我的 `DataRequest` 类,我想使用这个变量值 `(key.getSocketTimeout())` 在我的 `clientHttpRequestFactory()` 方法而不是使用硬编码的400值。做这件事的最佳有效方法是什么?
现在我正在使用 `Inversion of Control` 和路过 `RestTemplate` 在构造函数中共享 `RestTemplate` 在我的所有任务对象之间。我现在不知道怎么用 `key.getSocketTimeout()` 我的价值 `clientHttpRequestFactory()` 方法。我认为这主要是如何使用的设计问题 `RestTemplate` 在这里效率很高,这样我就可以 `key.getSocketTimeout()` 我的价值 `clientHttpRequestFactory()` 方法。
我已经简化了代码,这样我的想法就很清楚我要做什么,我正在使用Java7。使用 `ThreadLocal` 这是我唯一的选择还是有更好的优化方法?
2条答案
按热度按时间w7t8yxp51#
threadlocal是一种传递动态值的方法,通常您会通过方法属性传递动态值,但您使用的是一个您不能/不想更改的api。
您可以在线程堆栈的某个级别设置threadlocal(可能是包含多个值的数据结构),并可以在堆栈的更高级别使用它。
这是最好的方法吗?不,您真的应该在方法调用链上传递值,但有时这是不实际的。
你能举个例子说明我的代码在threadlocal中是什么样子的吗
你可以从
你可以这样做
为了得到你能做的价值
yshpjwxd2#
正如peter解释的,在这里使用threadlocal不是一个好主意。但是我也找不到一种方法来“将值传递给方法调用链”。
如果您使用普通的“apachehttpclient”,那么您可以创建一个httpget/put/etc,只需调用
httpRequest.setConfig(myRequestConfig)
. 换句话说:为每个请求设置一个请求配置(如果请求中没有设置任何内容,则从HttpClient
执行请求的)。相比之下
RestTemplate
电话createRequest(URI, HttpMethod)
(定义见HttpAccessor
)使用ClientHttpRequestFactory
. 换句话说:没有为每个请求设置请求配置的选项。我不知道为什么spring不使用这个选项,它似乎是一个合理的功能需求(或者我仍然缺少一些东西)。
关于“他们可以毫无控制地轰炸我们的服务”的一些注解:
这是使用
PoolingHttpClientConnectionManager
:通过设置适当的最大值,在同一时间内使用的连接数不能超过指定的最大连接数(因此请求正在运行)。这里的假设是您重复使用相同的RestTemplate
每个请求的示例(从而连接管理器)。要提前捕获泛洪,请在线程池中指定最大等待任务数,并设置适当的错误处理程序(使用
workQueue
以及handler
在这个构造函数中)。