RestTemplate线程安全吗?

时间:2014-04-10 13:30:03

标签: java spring rest thread-safety

Spring RestTemplate线程安全吗?那是

  • RestTemplate策略对象,多个连接可以安全地共享。
  • RestTemplate连接对象(如数据库连接),在使用时无法共享,需要为每个连接重新创建或汇集。

4 个答案:

答案 0 :(得分:76)

RestTemplate is thread safe(强调补充):

  

从概念上讲,它与JdbcTemplateJmsTemplate以及Spring Framework和其他项目组合项目中的各种其他模板非常相似。这意味着,例如, RestTemplate一旦构建就是线程安全的


RestTemplate类的对象不会更改任何状态信息来处理HTTP:该类是策略设计模式的一个实例,而不是像连接对象。如果没有状态信息,则如果共享RestTemplate对象,则不会有不同的线程破坏或竞争状态信息。这就是线程可以共享这些对象的原因。

如果您检查the source code of RestTemplate,您会发现在构造对象后,它不会使用synchronized方法或volatile字段来提供线程安全性。因此,构建后修改RestTemplate对象是安全的。特别是,添加消息转换器是不安全的。

要为其提供消息转换器列表,您必须执行以下操作之一:

  • 使用RestTemplate(List<HttpMessageConverter<?>> messageConverters)构造函数。由于messageConverters的内部列表为final,因此safely publishes the list of message converters
  • 使用setMessageConverters(List<HttpMessageConverter<?>> messageConverters) mutator ,然后使用safely-publish更改的RestTemplate对象。在大多数实际使用案例中,使用具有<property name="messageConverters"><list>...的Spring bean定义作为bean will be safely published by the thread setting up the container
  • List.add返回的引用使用getMessageConverters(),然后安全地发布已更改的RestTemplate对象。但是,RestTemplate的文档未明确声明它返回可用于更改消息转换器列表的引用。当前的实现确实如此,但可能会更改实现以返回Collections.unmodifiableList或列表的副本。所以最好不要这样改变它。

请注意,第一种情况是在构造对象时设置消息转换器的唯一方法,因此 正确地说它一旦构造就是线程安全的&#34;

该类是Spring Framework的一部分,因此在几乎所有实际情况中,类的对象将被设置为Spring Application Context的一部分,使用第一个(使用构造函数的依赖注入)或第二个(使用依赖注入)一个setter)方法,因此可以保证安全地发布到多个线程。

答案 1 :(得分:1)

从库的角度来看,它是线程安全的。例如,getMessageConverters()是公共的,这意味着如果有人抓住列表并在库的目的之外修改它,那么它将导致问题(甚至是setter方法,如果在RestTemplate实例化之后的任何时候调用它 - 显然,当被其他线程使用时,繁荣!)。这可能是Ross发生的事情(没有足够的声誉回复答案,但我正在备份线程安全和非线程安全的参数)

答案 2 :(得分:0)

好吧,虽然我可能会从导致这些问题的源代码控制中挖出旧代码。

我认为,即使在创建时进行同步,也存在另一个线程可以修改内部集合的情况。所以最好小心点。 看看旧代码,是的,它实际上是使用消息转换器。但只有在创作时同步。

restTemplate = new RestTemplate();

restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());

之后,与RestTemplate的唯一互动是:

return restTemplate.postForObject(url, object, clazz);

这也是最终抛出异常的行。

当然没有与消息转换器的交互(我们没有本地引用它)。

查看堆栈跟踪和spring源代码,错误发生在以下行:

for (HttpMessageConverter<?> converter : getMessageConverters()) {

那我们有什么?

  1. 我们可以同时访问messageConverters
  2. 如果我们的代码没有这样做,那么代码是做什么的?我没有答案。我当时的解决方案是每次创建一个新的RestTemplate,因为这个应用程序不关心性能。
  3. 总而言之,在某些情况下,事情可能不是线程安全的,当然如果您直接使用消息转换器。这种情况虽然很奇怪,但我认为发布它会很有用。

答案 3 :(得分:-1)

讨厌不同意上面接受的答案(强调添加),但不是不是线程安全。即使在创作之后。在内部,它正在玩ArrayLists,我没有挖掘源。我见过太多这些:

java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at org.springframework.web.client.RestTemplate$AcceptHeaderRequestCallback.doWithRequest(RestTemplate.java:677)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:567)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:545)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:253)