RestTemplate线程安全吗?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RestTemplate线程安全吗?相关的知识,希望对你有一定的参考价值。
Spring RestTemplate
线程安全吗?那是
RestTemplate
是一个策略对象,多个连接可以安全地共享。要么RestTemplate
是一个连接对象(如数据库连接),在使用时无法共享,并且需要为每个连接重新创建或汇集。
RestTemplate
is thread safe(重点补充):
从概念上讲,它与
JdbcTemplate
,JmsTemplate
以及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
或列表的副本。所以最好不要这样改变它。
请注意,第一种情况是在构造对象时设置消息转换器的唯一方法,因此说“一旦构造就是线程安全的”是正确的。
该类是Spring Framework的一部分,因此在几乎所有实际情况中,类的对象将被设置为Spring Application Context的一部分,使用第一个(使用构造函数的依赖注入)或第二个(使用setter的依赖注入)方法,因此将保证安全地发布到多个线程。
从图书馆的角度来看,它是线程安全的。例如,getMessageConverters()是公共的,这意味着如果有人抓住列表并在库的目的之外修改它,那么它将导致问题(甚至是setter方法,如果在RestTemplate实例化之后的任何时候调用它 - 显然,当被其他线程使用时,繁荣!)。这可能是Ross发生的事情(没有足够的声誉回复答案,但我正在备份线程安全和非线程安全的参数)
好吧,虽然我可能会从导致这些问题的源代码控制中挖掘旧代码。
我认为,即使在创建时进行同步,也存在另一个线程可以修改内部集合的情况。所以最好小心点。看看旧代码,是的,它实际上是使用消息转换器。但只有在创作时同步。
restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
之后,与RestTemplate的唯一交互就是:
return restTemplate.postForObject(url, object, clazz);
这也是最终抛出异常的行。
当然没有与消息转换器的交互(我们没有本地引用它)。
查看堆栈跟踪和spring源代码,此行发生错误:
for (HttpMessageConverter<?> converter : getMessageConverters()) {
那么我们有什么?
- 我们可以同时访问messageConverters
- 如果我们的代码没有这样做,那么代码做了什么?我没有答案。我当时的解决方案是每次创建一个新的RestTemplate,因为这个应用程序不关心性能。
总而言之,在某些情况下,事情可能不是线程安全的,当然如果您直接使用消息转换器。这种情况虽然很奇怪,但我认为发布它会很有用。
讨厌不同意上面接受的答案(强调添加),但不是不是线程安全。即使在创作之后。在内部,它正在玩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)
以上是关于RestTemplate线程安全吗?的主要内容,如果未能解决你的问题,请参考以下文章