Te doy la bienvenida a nuestra página, aquí vas a hallar la resolución que buscabas.
Solución:
Debido a que hay muchos conceptos erróneos, aquí voy a aclarar algunas cosas.
Spring ha declarado oficialmente que desaprobarán RestTemplate
en el futuro, así que si puedes, usa WebClient
si quiere estar lo más preparado posible para el futuro.
como se indica en la API RestTemplate
NOTA: A partir de 5.0, el reactivo no bloqueante
org.springframework.web.reactive.client.WebClient
ofrece una alternativa moderna a laRestTemplate
con soporte eficiente para sincronización y async, así como escenarios de transmisión. losRestTemplate
quedará obsoleto en una versión futura y no se agregarán nuevas funciones importantes en el futuro. Ver elWebClient
sección de la documentación de referencia de Spring Framework para obtener más detalles y código de ejemplo.
Aplicación no reactiva
Si su aplicación es una aplicación no reactiva (que no devuelve flujos o monos a los clientes que llaman), lo que debe hacer es usar block()
si necesita el valor. Por supuesto que puedes usar Mono
o Flux
internamente en su aplicación pero al final debe llamar block()
para obtener el valor concreto que necesita para devolver al cliente que llama.
Uso de aplicaciones no reactivas tomcat
como la implementación del servidor subyacente, que es un servidor basado en servlet que asignará 1 subproceso por solicitud para que no obtenga las ganancias de rendimiento que obtiene con una aplicación reactiva.
Aplicación reactiva
Si por el contrario tienes una aplicación reactiva, nunca bajo ninguna circunstancia deberías llamar block()
en su aplicación. El bloqueo es exactamente lo que dice, bloqueará un hilo y bloqueará la ejecución de ese hilo hasta que pueda seguir adelante, esto es malo en un mundo reactivo.
Tampoco deberías llamar subscribe
en su aplicación a menos que su aplicación sea el consumidor final de la respuesta. Por ejemplo, si está llamando a una API para obtener datos y escribir en una base de datos a la que está conectada su aplicación. Su aplicación de backend es el consumidor final. Si un cliente externo está llamando a su backend (por ejemplo, una aplicación de reacción, angular, cliente móvil, etc., etc.), el cliente externo es el consumidor final y es el que se suscribe. No tú.
La implementación del servidor predeterminado subyacente aquí es un netty
servidor que no es un servlet, servidor basado en eventos que no asigne un hilo a cada solicitud, el servidor en sí es independiente del hilo y cualquier hilo disponible manejará cualquier cosa en cualquier momento durante cualquier solicitud.
La documentación de webflux establece claramente que tanto los servidores compatibles con servlet 3.1+, tomcat y jetty, se pueden usar con webflux como con servidores que no son serlet, netty y undertow.
¿Cómo sé qué aplicación tengo?
Spring dice que si tienes ambos spring-web
y spring-webflux
en el classpath, la aplicación favorecerá spring-web
y, por defecto, inicie una aplicación no reactiva con un servidor Tomcat subyacente.
Este comportamiento se puede anular manualmente si es necesario como estados de primavera.
Sumando ambos
spring-boot-starter-web
yspring-boot-starter-webflux
Los módulos en su aplicación dan como resultado Spring Boot que configura automáticamente Spring MVC, no WebFlux. Este comportamiento ha sido elegido porque muchos desarrolladores de Spring agreganspring-boot-starter-webflux
a su aplicación Spring MVC para usar el WebClient reactivo. Aún puede hacer cumplir su elección configurando el tipo de aplicación elegido enSpringApplication.setWebApplicationType(WebApplicationType.REACTIVE)
.
El “marco de Spring WebFlux”
Entonces, ¿cómo implementar WebClient
@Retryable(maxAttempts = 4,
value = java.net.ConnectException.class,
backoff = @Backoff(delay = 3000, multiplier = 2))
public ResponseEntity getResponse(String url)
return webClient.get()
.uri(url)
.exchange()
.flatMap(response -> response.toEntity(String.class))
.block();
Esta es la implementación más fácil y menos intrusiva. Por supuesto, necesita crear un cliente web adecuado en tal vez un @Bean
y conectarlo automáticamente a su clase.
Lo primero que debe comprender es si necesita llamar .block()
también podrías quedarte con RestTemplate
, usar WebClient no le reportará nada.
Debe comenzar a pensar en términos reactivos si desea beneficiarse del uso de WebClient. Un proceso reactivo es en realidad solo una secuencia de pasos, la entrada de cada paso es la salida del paso anterior. Cuando entra una solicitud, su código crea la secuencia de pasos y regresa inmediatamente liberando el hilo http. Luego, el marco usa un grupo de subprocesos de trabajo para ejecutar cada paso cuando la entrada del paso anterior está disponible.
El beneficio es una gran ganancia en la capacidad de aceptar solicitudes de la competencia con el pequeño costo de tener que repensar la forma en que escribe el código. Su aplicación solo necesitará un grupo muy pequeño de subprocesos http y otro grupo muy pequeño de subprocesos de trabajo.
Cuando su método de controlador devuelve un Mono
o Flux
, lo ha hecho bien y no habrá necesidad de llamar block()
.
Algo como esto en su forma más simple:
@GetMapping(value = "endpoint", produces = MediaType.TEXT_PLAIN_VALUE)
@ResponseBody
@ResponseStatus(OK)
public Mono controllerMethod()
final UriComponentsBuilder builder =
UriComponentsBuilder.fromHttpUrl("http://base.url/" + "endpoint")
.queryParam("param1", "value");
return webClient
.get()
.uri(builder.build().encode().toUri())
.accept(APPLICATION_JSON_UTF8)
.retrieve()
.bodyToMono(String.class)
.retry(4)
.doOnError(e -> LOG.error("Boom!", e))
.map(s ->
// This is your transformation step.
// Map is synchronous so will run in the thread that processed the response.
// Alternatively use flatMap (asynchronous) if the step will be long running.
// For example, if it needs to make a call out to the database to do the transformation.
return s.toLowerCase();
);
Pasar a pensar en reactivo es un cambio de paradigma bastante grande, pero vale la pena el esfuerzo. Aguanta, realmente no es tan difícil una vez que puedes entender que no tienes ningún código de bloqueo en toda tu aplicación. Construya los pasos y devuélvalos. Luego, deje que el marco gestione las ejecuciones de los pasos.
Me complace brindar más orientación si algo de esto no está claro.
Recuerda divertirte 🙂
Reseñas y calificaciones de la guía
Tienes la posibilidad dar visibilidad a este post si te fue útil.