2014-01-20 107 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,这样你就可以构建一个实例,并把所有的任务分享。这将更有效率,因为您可以消除每项任务的建设成本,并减少垃圾收集器的负载。