Est-ce qu'un Spring RestTemplate
est thread-safe? C'est
RestTemplate
un objet de stratégie que plusieurs connexions peuvent partager en toute sécurité. oRestTemplate
un objet de connexion (comme une connexion à une base de données), qui ne peut pas être partagé pendant son utilisation, et nécessite une nouvelle création ou un regroupement pour chaque connexion.RestTemplate
est thread-safe (emphase ajoutée):
Conceptuellement, il est très similaire à
JdbcTemplate
,JmsTemplate
et aux divers autres modèles trouvés dans Spring Framework et dans d'autres projets de portefeuille. Cela signifie, par exemple, que leRestTemplate
est thread-safe une fois construit
Les objets de la classe RestTemplate
ne modifient aucune de leurs informations d'état pour traiter HTTP: la classe est une instance du modèle de conception Strategy, plutôt que d'être comme un objet de connexion. Sans information d'état, il n'y a aucune possibilité que différents threads corrompent ou informations d'état de course s'ils partagent un objet RestTemplate
. 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é des threads après la construction de l'objet. Il est donc pas sûr de modifier un objet RestTemplate
après la construction. En particulier, il n'est pas sûr d'ajouter un convertisseur de messages.
Pour lui fournir une liste de convertisseurs de messages, vous devez effectuer l'une des opérations suivantes:
RestTemplate(List<HttpMessageConverter<?>> messageConverters)
. Comme la liste interne de messageConverters
est final
, ceci publie en toute sécurité la liste des convertisseurs de messages .setMessageConverters(List<HttpMessageConverter<?>> messageConverters)
et puis publiez en toute sécurité l'objet RestTemplate
modifié. Utiliser une définition de bean Spring qui a un <property name="messageConverters"><list>...
Fait cela, car le bean sera publié en toute sécurité par le thread configurant le conteneur dans la plupart des cas d'utilisation pratiques.List.add
Sur la référence renvoyée par getMessageConverters()
, puis publiez en toute sécurité l'objet RestTemplate
modifié. Cependant, la documentation de RestTemplate
n'indique pas explicitement qu'elle renvoie une référence qui peut être utilisée pour modifier la liste des convertisseurs de messages. L'implémentation actuelle le fait, mais il est possible que l'implémentation soit modifiée pour renvoyer un Collections.unmodifiableList
Ou une copie de la liste. Il serait donc préférable de ne pas le changer de cette façon.Notez que le premier cas est le seul moyen de configurer les convertisseurs de messages lors de la construction de l'objet, donc il est correct de dire qu'il "est thread-safe une fois construit ".
La classe fait partie du Spring Framework, donc dans presque tous les cas pratiques, les objets de la classe seront configurés dans le cadre d'un contexte d'application Spring, en utilisant le premier (injection de dépendance à l'aide d'un constructeur) ou le second (injection de dépendance à l'aide d'un setter) et serait donc garanti d'être publié en toute sécurité sur plusieurs threads.
Il est thread-safe du point de vue de la bibliothèque. Par exemple, le getMessageConverters () est public, ce qui signifie que si quelqu'un s'accroche à la liste et la modifie en dehors du but de la bibliothèque, cela causera des problèmes (et même la méthode setter, si elle est appelée à tout moment après l'instanciation RestTemplate - et tout en étant utilisé par d'autres threads évidemment, boom!). C'est probablement ce qui est arrivé à Ross (pas assez de réputation pour répondre à la réponse, mais je sauvegarde les arguments thread-safe et non thread-safe)
D'accord, bien que je puisse extraire l'ancien code du contrôle de source qui a causé ces problèmes.
Je pense qu'il serait juste de dire que même lors de la synchronisation à la création, il existe des circonstances où un autre thread peut modifier les collections internes. Il vaut donc mieux être prudent. En regardant l'ancien code, oui, il utilisait en fait un convertisseur de messages. Mais uniquement lors de la synchronisation lors de 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 également la ligne qui lève finalement l'exception.
Il n'y a bien sûr aucune interaction avec le convertisseur de messages (nous n'avons aucune référence locale à lui).
En regardant la stacktrace et le code source de Spring, l'erreur s'est produite sur cette ligne:
for (HttpMessageConverter<?> converter : getMessageConverters()) {
Alors qu'est-ce que nous avons?
Donc, en résumé, il y a des circonstances où les choses peuvent ne pas être thread-safe, certainement si vous jouez directement avec les convertisseurs de messages. Ce cas est cependant étrange, mais j'ai pensé qu'il serait utile de le publier.