2014-01-20 106 views
12

我正在開發一個項目,在該項目中,我需要對運行Restful Service的服務器進行HTTP URL調用,該服務器將響應作爲JSON字符串返回。如何在多線程環境中有效使用RestTemplate?

下面是一個使用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; 
    } 
} 

現在我在類5000 times sequery中調用getData方法的另一個類DemoTest中的代碼如下entially -

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靜態的,那麼,我認爲作爲DemoTest類措施成效註釋掉一號線2號線和後相比,非靜態RestTemplate更好的性能端到端。

一般來說,在多線程環境中使用RestTemplate的正確方法是什麼?目前我按順序依次調用getData方法5000次,但有些客戶會以多線程方式調用它,所以需要知道在多線程環境中使用RestTemplate的最佳方式是什麼。

可能是在ConnectionFactory中使用RestTemplate的構造函數?有什麼想法嗎?

更新: -

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; 
    } 
} 
+0

可能的重複[如何提高性能,同時使用ExecutorService線程超時功能?](http://stackoverflow.com/questions/21241036/how-to-improve-the-performance-while-using-executorservice- with-thread-timeout-c) –

回答

13

糾正我,如果我不明白你的問題。它看起來非常類似於前一個here。我們發現RestTemplate是線程安全的。因此,沒有理由不把它分享到任何有意義的地方,即。無論您使用何種方式。 你的例子似乎是完美的地方。

如您所述,爲每個Task實例重新創建一個新實例RestTemplate是浪費資源。

我會在TimeoutThreadExample中創建RestTemplate,並將其作爲構造函數參數傳遞給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; 
    } 
} 

這樣你共享所有Task對象之間的RestTemplate實例。

請注意,RestTemplate使用SimpleClientHttpRequestFactory創建它的連接。

+0

我明白了。所以簡而言之,它們都是相同的。在Task類中做一個靜態的?或者通過傳遞物體來使用DI? – AKIWEB

+2

RestTemplate是線程安全的,但您還必須確保下屬http連接管理器是線程安全的,例如,使用'org.apache.commons.httpclient.MultiThreadedHttpConnectionManager'(請注意我使用的是commons-httpclient 3.1,所以這可能不適用於其他版本) – Taylor

+0

另一個重複:http://stackoverflow.com/a/21241233/ 1103872。顯然OP在這裏有兩個身份。 –

4

我有我的多線程安全的單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

0

一個RestTemplateis thread safe once constructed,這樣你就可以構建一個實例,並把所有的任務分享。這將更有效率,因爲您可以消除每項任務的建設成本,並減少垃圾收集器的負載。