如何使用RestTemplate为每个请求设置RequestConfiguration? [英] How to set RequestConfiguration per request using RestTemplate?

查看:1285
本文介绍了如何使用RestTemplate为每个请求设置RequestConfiguration?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个供客户使用的库,他们正在传递 DataRequest 对象,该对象有 userid 超时以及其中的一些其他字段。现在我使用这个 DataRequest 对象来创建一个URL,然后使用 RestTemplate 进行HTTP调用,然后我的服务返回一个JSON响应,我用它来制作一个 DataResponse 对象,然后将这个 DataResponse 对象返回给它们。

I have a library which is being used by customer and they are passing DataRequest object which has userid, timeout and some other fields in it. Now I use this DataRequest object to make a URL and then I make an HTTP call using RestTemplate and my service returns back a JSON response which I use it to make a DataResponse object and return this DataResponse object back to them.

以下是我的 DataClient 类,客户通过传递 DataRequest 对象它。我在 DataRequest 中使用客户传递的超时值来超时请求,如果在 getSyncData 方法中花费太多时间。

Below is my DataClient class used by customer by passing DataRequest object to it. I am using timeout value passed by customer in DataRequest to timeout the request if it is taking too much time in getSyncData method.

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 class:

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.
    }
}

我们公司内的客户将像我这样使用我的库通过在我们的代码库中使用我的工厂显示如下 -

Customer within our company will use my library like this as shown below by using my factory in their code base -

// 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);

我正在实施同步调用async + waiting 因为我想用线程数限制它们,否则它们可以在没有任何控制的情况下轰炸我们的服务。

I am implementing sync call as async + waiting since I want to throttle them with the number of threads otherwise they can bombard our service without any control.

问题陈述: -

我将在我的 DataRequest 套接字超时的超时变量$ c> class我想在我的 clientHttpRequestFactory()中使用该变量值(key.getSocketTimeout())方法而不是使用硬编码400值。这样做的最佳和最有效的方法是什么?

I am going to add another timeout variable called socket timeout in my DataRequest class and I want to use that variable value (key.getSocketTimeout()) in my clientHttpRequestFactory() method instead of using hard coded 400 value. What is the best and efficient way to do that?

现在我正在使用 Inversion of Control 并传递 RestTemplate 在构造函数中共享所有Task对象之间的 RestTemplate 。我现在很困惑如何在我的 clientHttpRequestFactory()方法中使用 key.getSocketTimeout()值。我认为这主要是如何有效地使用 RestTemplate 的设计问题,这样我就可以使用 key.getSocketTimeout()我的 clientHttpRequestFactory()方法中的值。

Right now I am using Inversion of Control and passing RestTemplate in a constructor to share the RestTemplate between all my Task objects. I am confuse now how to use key.getSocketTimeout() value in my clientHttpRequestFactory() method. I think this is mostly design question of how to use RestTemplate efficiently here so that I can use key.getSocketTimeout() value in my clientHttpRequestFactory() method.

我已经简化了代码,以便明白我想要的想法要做,我在Java 7.使用 ThreadLocal 是我在这里的唯一选择还是有更好的优化方式?

I have simplified the code so that idea gets clear what I am trying to do and I am on Java 7. Using ThreadLocal is the only option I have here or there is any better and optimized way?

推荐答案

正如 Peter解释一样,使用ThreadLocal并不是一个好主意这里。
但我也找不到将值传递给方法调用链的方法。

As Peter explains, using ThreadLocal is not a good idea here. But I also could not find a way to "pass the value up the chain of method calls".

如果使用普通的Apache HttpClient,那么你可以创建一个HttpGet / Put / etc。并简单地调用
httpRequest.setConfig(myRequestConfig)。换句话说:为每个请求设置一个请求配置
(如果请求中没有设置任何内容,则使用执行请求的 HttpClient 中的请求配置)。

If you use plain "Apache HttpClient", you can create an HttpGet/Put/etc. and simply call httpRequest.setConfig(myRequestConfig). In other words: set a request configuration per request (if nothing is set in the request, the request configuration from the HttpClient which executes the request is used).

相比之下, RestTemplate
调用 createRequest(URI,HttpMethod)(在 HttpAccessor
使用 ClientHttpRequestFactory 。换句话说:没有选项可以为每个请求设置请求配置。

我不确定为什么Spring将这个选项排除在外,这似乎是一个合理的功能要求(或者我可能仍然遗漏了一些东西)。

In contrast, the RestTemplate calls createRequest(URI, HttpMethod) (defined in HttpAccessor) which uses the ClientHttpRequestFactory. In other words: there is no option to set a request configuration per request.
I'm not sure why Spring left this option out, it seems a reasonable functional requirement (or maybe I'm still missing something).

关于他们可以在没有任何控制权的情况下轰炸我们的服务的一些注意事项:

Some notes about the "they can bombard our service without any control":


  • 这是使用<$ c的原因之一$ c> PoolingHttpClientConnectionManager :
    通过设置适当的最大值,同时永远不会超过指定的最大连接数(因此请求运行)。这里的假设是你为每个请求重复使用相同的 RestTemplate 实例(以及连接管理器)。

  • 要捕获一个洪泛之前,在线程池中指定最大等待任务量并设置正确的错误处理程序
    (使用 workQueue 处理程序此构造函数)。

  • This is one of the reasons to use the PoolingHttpClientConnectionManager: by setting the appropriate maximum values, there can never be more than the specified maximum connections in use (and thus requests running) at the same time. The assumption here is that you re-use the same RestTemplate instance (and thus connection manager) for each request.
  • To catch a flood earlier, specify a maximum amount of waiting tasks in the threadpool and set a proper error-handler (use the workQueue and handler in this constructor).

这篇关于如何使用RestTemplate为每个请求设置RequestConfiguration?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆