12

私は、お客様が使用しているライブラリを持っており、オブジェクトにuserid,timeoutなどのフィールドを渡しています。ここでこのDataRequestオブジェクトをURLに使用して、RestTemplateを使用してHTTP呼び出しを行い、私のサービスはDataResponseオブジェクトを作成し、このDataResponseオブジェクトを戻すJSON応答を返します。RestTemplateを使用してリクエストごとにRequestConfigurationを設定するにはどうすればよいですか?

以下はDataRequestオブジェクトを渡してお客様が使用しているDataClientクラスです。 getSyncDataメソッドであまりにも多くの時間がかかる場合、私はDataRequestの顧客が渡したタイムアウト値をタイムアウトに使用しています。

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

お客様がこのように私のライブラリを使用します - 私はsync call as async + waitingを実装しています

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

そうでなければ何の制御もせずに私たちのサービスを砲撃することができます。

問題文: -

私は私のDataRequestクラスにsocket timeoutと呼ばれる別のタイムアウト変数を追加するつもりですし、私が代わりにハードコードされた400値を使用しての私のclientHttpRequestFactory()方法でその変数値(key.getSocketTimeout())を使用します。それを行うための最も効率的な方法は何ですか?

今私はすべての私の仕事のオブジェクトの間でRestTemplateを共有するためにコンストラクタでInversion of ControlRestTemplateを渡しています。私はclientHttpRequestFactory()メソッドでkey.getSocketTimeout()の値を使う方法を今混同しています。これは、RestTemplateを効率的にここで使用する方法の設計上の問題であると私のclientHttpRequestFactory()メソッドでkey.getSocketTimeout()の値を使用できるようにするためです。

アイデアが私がやろうとしていることが明確になるようにコードを単純化しました。私はJava 7を使用しています。ThreadLocalは私がここにいる唯一の選択肢です。

答えて

1

ThreadLocalは通常はメソッドのプロパティで渡す動的値を渡す方法ですが、変更できないAPIを使用しています。

スレッドスタック内のあるレベルでThreadLocal(複数の値を含む可能性のあるデータ構造)を設定し、それをスタックまでさらに使用することができます。

これが最善のアプローチですか?いいえ、あなたは実際にメソッド呼び出しの連鎖の値を渡すべきですが、時にはこれは実用的ではありません。

あなたはあなたが

SOCKET_TIMEOUT .set(key.getSocketTimeout()); 

を行うことができ、それを設定するには

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

で開始される可能性があります私のコードはThreadLocalの

で次のようになります方法の例を提供することができますあなたが行うことができる価値を得るために

long socketTimeout = SOCKET_TIMEOUT.get(); 
+0

私はここで使用できるオプションは何ですか?何かご意見は? – user1950349

+0

@ user1950349 AFAICSあなたの他のオプションは、ThreadLocalを使うよりも悪くなるでしょう。 –

+0

私は参照してください。私のコードがどのように 'ThreadLocal'のように見えるかの例を提供できますか?いくつかの負荷テストを行い、パフォーマンスに影響するかどうかを確認できます。私は以前ThreadLocalで作業していませんでしたが、ドキュメントを読むともっと混乱するので、私のソリューションでどのように使うことができるのかよく分かりません。 – user1950349

4

Peter explainsとして、ThreadLocalを使用するのは良い考えではありません。 しかし、私は "メソッド呼び出しの連鎖の価値を渡す"方法も見つけられませんでした。

プレーンな「Apache HttpClient」を使用している場合は、HttpGet/Put/etcを作成できます。単に httpRequest.setConfig(myRequestConfig)と呼んでください。言い換えれば:要求ごとに要求構成を設定する (要求に何も設定されていない場合、要求を実行するHttpClientの要求構成が使用されます)。対照的に

ClientHttpRequestFactory使用(HttpAccessorで定義)RestTemplate コールcreateRequest(URI, HttpMethod)。言い換えると、要求ごとに要求構成を設定するオプションはありません。
なぜSpringがこのオプションを残しているのか分かりませんが、それは合理的な機能要件(または、おそらくまだ何かが欠けているようです)のようです。

「彼らは任意のコントロールなしに当社のサービスを砲撃することができます」に関するいくつかの注意事項:

  • これはPoolingHttpClientConnectionManager使用する理由の一つです:適切な最大値を設定することで を、より多くの存在になることはありません同時に使用されている特定の最大接続数(したがって実行要求数)ここでは、各要求に対して同じRestTemplateインスタンス(したがって接続マネージャー)を再使用することを前提としています。
  • floodを先にキャッチするには、スレッドプール内で待機するタスクの最大量を指定し、適切なエラーハンドラ を設定します(とhandlerthis constructorに使用します)。
+0

ええ、私は 'ThreadLocal'についてのポイントを得ましたが、ここで使用できる他のオプションはありますか?私がここで使うことができる方法がないように見えますか? – user1950349

+0

1)春のWebクライアントの機能要求を開きます。 2)Apache HttpClientを直接使用する(resttemplateは使用しない)、JsonレスポンスをDataObjectに「手動で」変換する(ホイールを幾分再発明するが、複雑ではない)。 – vanOekel

+0

私は機能要求を開くだろうと確信しています。私はApache HttpClientを長い時間使ってみましたが、マルチスレッド環境で効率的に動作させることができませんでした。可能であれば、私のソリューションでどのように普通の 'Apache HttpClient'を使うことができるかの例を挙げてください。それは大きな助けになるでしょうし、 'RestTemplate'と比較してどのように動作するかを見るためにいくつかの負荷テストを行います。 – user1950349

関連する問題