headers getforobject for example java spring rest thread-safety

java - getforobject - resttemplate spring boot post example



¿El subproceso RestTemplate es seguro? (4)

¿Un Spring RestTemplate es seguro para subprocesos? Es decir

  • Es un RestTemplate un objeto de estrategia que las conexiones múltiples pueden compartir de forma segura. o
  • Es un RestTemplate un objeto de conexión (como una conexión de base de datos), que no se puede compartir mientras está en uso, y requiere una RestTemplate creación o agrupamiento para cada conexión.

De acuerdo, aunque podría desenterrar el código anterior del control de código fuente que causaba estos problemas.

Creo que sería justo decir que incluso sincronizando en la creación existen circunstancias en las que otro hilo puede modificar las colecciones internas. Así que mejor ten cuidado. Mirando el código anterior, sí, en realidad estaba usando un convertidor de mensajes. Pero solo cuando está sincronizado en la creación.

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

Después de eso, la única interacción con RestTemplate fue con esto:

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

Esta es también la línea que eventualmente arroja la excepción.

Por supuesto, no hay interacción con el convertidor de mensajes (no tenemos referencia local).

Al observar el stacktrace y el código fuente del muelle, el error ocurrió en esta línea:

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

¿Entonces que tenemos?

  1. Tenemos acceso concurrente a messageConverters
  2. Si nuestro código no lo hizo, ¿qué código hizo? No tengo una respuesta. Mi solución en ese momento era crear una nueva RestTemplate cada vez, ya que el rendimiento no era una preocupación en esta aplicación.

Entonces, en resumen, hay circunstancias en las que las cosas pueden no ser seguras para subprocesos, por supuesto, si juegas con convertidores de mensajes directamente. Sin embargo, este caso es extraño, pero pensé que sería útil publicarlo.


Está protegido contra subprocesos desde el punto de vista de la biblioteca. Por ejemplo, getMessageConverters () es público. Esto significa que si alguien se agarra a la lista y la modifica fuera del propósito de la biblioteca, se generarán problemas (e incluso el método setter, si se llama en cualquier momento después de la instanciación de RestTemplate - y mientras está siendo utilizado por otros hilos obviamente, ¡boom!). Lo cual probablemente es lo que le sucedió a Ross (la reputación no es suficiente para responder a la respuesta, pero estoy respaldando los argumentos seguros para hilos y no para subprocesos)


Odio estar en desacuerdo con la respuesta aceptada arriba (énfasis agregado), pero no, no es seguro. Incluso después de la creación. Internamente está jugando con ArrayLists, no he buscado en la fuente. He visto demasiados de estos:

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 es seguro para subprocesos (énfasis añadido):

Conceptualmente, es muy similar a JdbcTemplate , JmsTemplate y las otras plantillas que se encuentran en Spring Framework y otros proyectos de cartera. Esto significa, por ejemplo, que RestTemplate es seguro para hilos una vez construido

Los objetos de la clase RestTemplate no cambian ninguna de sus informaciones de estado para procesar HTTP: la clase es una instancia del patrón de diseño de Estrategia, en lugar de ser como un objeto de conexión. Sin información de estado, no hay posibilidad de que diferentes hilos corrompan o RestTemplate información de estado si comparten un objeto RestTemplate . Es por eso que es posible que los hilos compartan estos objetos.

Si examina el código fuente de RestTemplate , verá que no utiliza métodos synchronized o campos volatile para proporcionar seguridad de subprocesos después de la construcción del objeto. Por lo tanto, no es seguro modificar un objeto RestTemplate después de la construcción. En particular, no es seguro agregar un convertidor de mensajes.

Para proporcionarle una lista de conversores de mensajes, debe hacer una de las siguientes cosas:

  • Utilice el RestTemplate(List<HttpMessageConverter<?>> messageConverters) . Como la lista interna de messageConverters es final , publica de forma segura la lista de convertidores de mensajes .
  • Utilice el setMessageConverters(List<HttpMessageConverter<?>> messageConverters) y luego safely-publish el objeto RestTemplate cambiado. El uso de una definición de Spring Bean que tiene un <property name="messageConverters"><list>... hace esto, ya que el bean se publicará con seguridad mediante el hilo que configura el contenedor en la mayoría de los casos prácticos.
  • Use List.add en la referencia devuelta por getMessageConverters() y luego publique de forma segura el objeto RestTemplate cambiado. Sin embargo, la documentación para RestTemplate no establece explícitamente que devuelve una referencia que se puede usar para alterar la lista de convertidores de mensajes. La implementación actual sí lo hace, pero posiblemente la implementación podría cambiarse para devolver Collections.unmodifiableList o una copia de la lista. Entonces, sería mejor no cambiarlo de esta manera.

Tenga en cuenta que el primer caso es el único medio para configurar los convertidores de mensajes al construir el objeto, por lo que es correcto decir que "es seguro para hilos una vez construido".

La clase es parte del Spring Framework, por lo que en casi todos los casos prácticos los objetos de la clase se configurarán como parte de un contexto de aplicación Spring, utilizando el primero (inyección de dependencia usando un constructor) o el segundo (inyección de dependencia usando un setter) métodos, por lo que se garantizaría que se publicara de forma segura en varios hilos.