Est RestTemplate thread-safe?
Est un Printemps RestTemplate
thread-safe"? C'est-à-dire
- est un
RestTemplate
un objet stratégique que plusieurs connexions peuvent partager en toute sécurité. ou - est un
RestTemplate
un objet de connexion (comme une connexion de base de données), qui ne peut pas être partagé en cours d'utilisation, et nécessite une nouvelle création, ou mise en commun, pour chaque connexion.
4 réponses
RestTemplate
is thread safe (non souligné dans l'original):
conceptuellement, il est très similaire au
JdbcTemplate
,JmsTemplate
, et les divers autres modèles trouvés dans le cadre du printemps et d'autres projets de portfolio. Cela signifie, par exemple, que leRestTemplate
est sans fil une fois construit
objets de la RestTemplate
class ne changent aucune de leurs informations d'État pour traiter HTTP: la classe est une instance du schéma de conception de la stratégie, plutôt que d'être comme un objet de connexion. Sans information d'état, il n'y a pas de possibilité de différents threads corrompant ou informations d'état de course si elles partagent un RestTemplate
objet. C'est pourquoi il est possible pour les threads de partager ces objets.
si vous examinez le code source de RestTemplate
vous verrez qu'il n'utilise pas les méthodes synchronized
ou les champs volatile
pour assurer la sécurité du fil après la construction de l'objet. Il est donc pas sûr de modifier un RestTemplate
objet après la construction. En particulier, il est dangereux d'ajouter un convertisseur de messages.
pour lui fournir une liste de convertisseurs de messages, vous devez faire l'un des suivants:
- utilisez le constructeur
RestTemplate(List<HttpMessageConverter<?>> messageConverters)
. Comme l' la liste interne demessageConverters
estfinal
, ce publie en toute sécurité la liste des convertisseurs de message . - utilisez le
setMessageConverters(List<HttpMessageConverter<?>> messageConverters)
mutateur et puis publier en toute sécurité l'objet modifiéRestTemplate
. L'utilisation d'une définition de haricot de printemps qui a un<property name="messageConverters"><list>...
le fait, car le haricot sera publié en toute sécurité par le fil de configuration du conteneur dans la plupart des pratiques les cas d'utilisation. - utiliser
List.add
sur la référence retournée pargetMessageConverters()
et ensuite publier en toute sécurité l'objet modifiéRestTemplate
. Cependant, la documentation deRestTemplate
n'indique pas explicitement qu'elle renvoie une référence qui peut être utilisée pour modifier la liste des convertisseurs de messages. La mise en œuvre actuelle Oui, mais peut-être la mise en œuvre pourrait être modifiée pour retourner unCollections.unmodifiableList
ou une copie de la liste. Il vaut peut-être mieux ne pas le changer de cette façon.
notez que le premier cas est le seul moyen de mettre en place les convertisseurs de message lors de la construction de l'objet, donc il est correct de dire qu'il"est filé en toute sécurité une fois construit".
la classe fait partie du cadre du ressort, de sorte que dans presque tous les cas pratiques les objets de la classe seront configurés dans un contexte D'Application du ressort, en utilisant le premier (injection de dépendances à l'aide d'un constructeur) ou le second (injection de dépendances à l'aide d'un setter).
Il est thread-safe à partir de la bibliothèque de point de vue. Par exemple, le getMessageConverters() est public ce qui signifie que si quelqu'un s'empare de la liste et la modifie en dehors du but de la bibliothèque alors il causera des problèmes (et même la méthode setter, si elle est appelée à tout moment après instanciation RestTemplate - et tout en étant utilisée par d'autres threads évidemment, boom!). Ce qui est probablement ce qui est arrivé à Ross (pas assez de réputation pour répondre à la réponse, mais je suis sauvegarder à la fois le "thread-safe" et pas "thread-safe" arguments)
D'accord, bien que je puisse extraire l'ancien code du contrôle source qui a causé ces problèmes.
je pense qu'il serait juste de dire que même la synchronisation sur la création il existe des circonstances où un autre fil peut modifier les collections internes. Donc il vaut mieux être prudent. En regardant l'ancien code, oui il utilisait en fait un convertisseur de messages. Mais seulement lorsqu'il est synchronisé sur la création.
restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
après cela la seule interaction avec RestTemplate était avec ceci:
return restTemplate.postForObject(url, object, clazz);
C'est aussi la ligne qui finit par jeter l'exception.
Il n'y a évidemment pas d'interaction avec le message convertisseur (nous n'avons pas de référence locale).
en regardant le stacktrace, et le code source du ressort, l'erreur s'est produite à cette ligne:
for (HttpMessageConverter<?> converter : getMessageConverters()) {
alors qu'est-ce qu'on a?
- nous avons concurrent accès aux convertisseurs de messages
- si notre code ne l'a pas fait, alors quel code l'a fait? Je n'ai pas de réponse. Ma solution à l'époque était de créer un nouveau RestTemplate à chaque fois que la performance n'était pas un problème dans cette application.
donc, en résumé, il ya des circonstances où les choses peuvent ne pas être thread sûr, certainement si vous deviez jouer avec les convertisseurs de messages directement. Ce cas est étrange, mais j'ai pensé qu'il serait utile de le publier.
Hate d'être en désaccord avec la accepté la réponse ci-dessus (emphase ajoutée), mais non ce n'est pas Thread-safe. Même après la création. À l'intérieur, il joue avec les ArrayLists, Je n'ai pas creusé dans la source. J'en ai vu trop:
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)