web-dev-qa-db-ja.com

マルチスレッド環境でRestTemplateを効率的に使用するには?

私は、Restful Serviceを実行しているサーバーに対してHTTP URL呼び出しを行う必要があるプロジェクトに取り組んでいます。このサーバーは、応答をJSON文字列として返します。

以下は、futurecallablesを使用しているメインコードです-

public class TimeoutThreadExample {

    private ExecutorService executor = Executors.newFixedThreadPool(10);

    public String getData() {
        Future<String> future = executor.submit(new Task());
        String response = null;

        try {
            response = future.get(100, TimeUnit.MILLISECONDS);
        } catch (TimeoutException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        return response;
    }
}

以下は、Taskインターフェイスを実装し、Callable...を使用するRestTemplateクラスです。

class Task implements Callable<String> {

    private RestTemplate restTemplate = new RestTemplate();

    public String call() throws Exception {

        String url = "some_url";
        String response = restTemplate.getForObject(url, String.class);

        return response;
    }
}

そして今、私は別のクラスDemoTestのコードを持っていますgetDataクラス5000 timesTimeoutThreadExampleメソッドを順番に呼び出します-

public class DemoTest { 
   public static void main(String[] args) {

        TimeoutThreadExample bc = new TimeoutThreadExample();

        for (int i = 0; i <= 5000; i++) {
        //  TimerTest timer = TimerTest.getInstance(); // line 1
            bc.getData();
        //  timer.getDuration(); // line 2
        }
    }
}       

したがって、私の質問はRestTemplateここでTask classで静的である必要があります。正しく表示されるように、RestTemplateの各リクエストの接続プール全体を再作成しています私が推測する方法..

注: RestTemplateを静的にした場合、RestTemplateクラスのline1とline2をコメントアウトした後、静的でないDemoTestと比較して、エンドツーエンドのパフォーマンスが向上します。パフォーマンスを測定します。

一般的に、マルチスレッド環境でRestTemplateを使用する正しい方法は何ですか?現在、私はgetDataメソッドを1つずつ順番に5000回呼び出していますが、一部の顧客はマルチスレッドで呼び出すため、マルチスレッド環境でRestTemplateを使用する最良の方法を知る必要があります。

RestTemplateコンストラクターでConnectionFactoryを使用することはできますか?何かご意見は?

更新:-

public class TimeoutThreadExample {

    private ExecutorService executor = Executors.newFixedThreadPool(10);
    private RestTemplate restTemplate = new RestTemplate();

    public String getData() {
        Future<String> future = executor.submit(new Task(restTemplate));
        String response = null;

        try {
            response = future.get(100, TimeUnit.MILLISECONDS);
        } catch (TimeoutException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        return response;
    }
}

そして、私のTaskClassの下に-

class Task implements Callable<String> {

    private RestTemplate restTemplate;

    public Task(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public String call() throws Exception {

        String url = "some_url";
        String response = restTemplate.getForObject(url, String.class);

        return response;
    }
}
14
AKIWEB

あなたの質問を理解できなかった場合は私を修正してください。前のものと非常に似ているようです here

そこで、RestTemplateはスレッドセーフであると判断しました。したがって、意味のあるところならどこでも共有しない理由はありません。同じ方法で使用しているところはどこでも。あなたの例はそうするのに最適な場所のようです。

あなたが述べたように、RestTemplateインスタンスごとにTaskの新しいインスタンスを再作成するのは無駄です。

RestTemplateTimeoutThreadExampleを作成し、それをコンストラクター引数としてTaskに渡します。

class Task implements Callable<String> {

    private RestTemplate restTemplate;

    public Task(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public String call() throws Exception {

        String url = "some_url";
        String response = restTemplate.getForObject(url, String.class);

        return response;
    }
}

この方法で、すべてのRestTemplateオブジェクト間でTaskインスタンスを共有します。

RestTemplateSimpleClientHttpRequestFactoryを使用して接続を作成することに注意してください。

16

私はマルチスレッドセーフシングルトンを持っていますREST春にこのように配線されたテンプレート:

<bean class="org.Apache.commons.httpclient.params.HttpConnectionManagerParams" id="httpConnectionManagerParams">
    <property name="connectionTimeout" value="10000"/>
</bean>
<bean class="org.Apache.commons.httpclient.MultiThreadedHttpConnectionManager" id="httpConnectionManager">
    <property name="params" ref="httpConnectionManagerParams"/>
</bean>
<bean class="org.Apache.commons.httpclient.params.HttpClientParams" id="httpClientParams">
    <property name="authenticationPreemptive" value="true"/>
    <property name="soTimeout" value="10000"/>
</bean>
<bean class="org.Apache.commons.httpclient.HttpClient" id="httpClient">
    <constructor-arg ref="httpClientParams"/>
    <constructor-arg ref="httpConnectionManager"/>
</bean>
<bean class="org.springframework.http.client.CommonsClientHttpRequestFactory" id="httpClientFactory">
    <constructor-arg ref="httpClient"/>
</bean>
<bean class="org.springframework.security.oauth.consumer.client.OAuthRestTemplate" id="restTemplate">
    <constructor-arg ref="httpClientFactory"/>
    <constructor-arg ref="myResource"/>
    <property name="messageConverters">
        <list>
            <ref bean="marshallingHttpMessageConverter"/>
        </list>
    </property>
</bean>

OAuthRestTemplateを使用していることに注意してください。また、myResourceはoauth関係ないので省略したリソースを参照しています。OAuthRestTemplateの代わりにorg.springframework.web.client.RestTemplatehttp://docs.spring.io/spring/docs/3.2.4.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html

4
Taylor

RestTemplate一度構築するとスレッドセーフになります 。したがって、1つのインスタンスを構築し、すべてのタスクで共有できます。各タスクから構築コストを排除し、ガベージコレクターの負荷を軽減するため、これははるかに効率的です。

1
Raedwald