如何使用restemplate为每个请求设置requestconfiguration?

jm2pwxwz  于 2021-07-03  发布在  Java
关注(0)|答案(2)|浏览(513)

我有一个图书馆,客户正在使用,他们正在通过 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` 这是我唯一的选择还是有更好的优化方法?
w7t8yxp5

w7t8yxp51#

threadlocal是一种传递动态值的方法,通常您会通过方法属性传递动态值,但您使用的是一个您不能/不想更改的api。
您可以在线程堆栈的某个级别设置threadlocal(可能是包含多个值的数据结构),并可以在堆栈的更高级别使用它。
这是最好的方法吗?不,您真的应该在方法调用链上传递值,但有时这是不实际的。
你能举个例子说明我的代码在threadlocal中是什么样子的吗
你可以从

static final ThreadLocal<Long> SOCKET_TIMEOUT = new ThreadLocal<>();

你可以这样做

SOCKET_TIMEOUT .set(key.getSocketTimeout());

为了得到你能做的价值

long socketTimeout = SOCKET_TIMEOUT.get();
yshpjwxd

yshpjwxd2#

正如peter解释的,在这里使用threadlocal不是一个好主意。但是我也找不到一种方法来“将值传递给方法调用链”。
如果您使用普通的“apachehttpclient”,那么您可以创建一个httpget/put/etc,只需调用 httpRequest.setConfig(myRequestConfig) . 换句话说:为每个请求设置一个请求配置(如果请求中没有设置任何内容,则从 HttpClient 执行请求的)。
相比之下 RestTemplate 电话 createRequest(URI, HttpMethod) (定义见 HttpAccessor )使用 ClientHttpRequestFactory . 换句话说:没有为每个请求设置请求配置的选项。
我不知道为什么spring不使用这个选项,它似乎是一个合理的功能需求(或者我仍然缺少一些东西)。
关于“他们可以毫无控制地轰炸我们的服务”的一些注解:
这是使用 PoolingHttpClientConnectionManager :通过设置适当的最大值,在同一时间内使用的连接数不能超过指定的最大连接数(因此请求正在运行)。这里的假设是您重复使用相同的 RestTemplate 每个请求的示例(从而连接管理器)。
要提前捕获泛洪,请在线程池中指定最大等待任务数,并设置适当的错误处理程序(使用 workQueue 以及 handler 在这个构造函数中)。

相关问题