Cómo Quarkus combina MicroProfile y Spring

¡Hola a todos! Y aquí está la tercera publicación de la serie sobre Quarkus.

Cómo Quarkus combina MicroProfile y Spring

Al desarrollar microservicios en Java, a menudo se considera que Eclipse MicroProfile y Spring Boot son API separadas e independientes entre sí. Por defecto, los programadores tienden a usar las API con las que ya están familiarizados, ya que aprender nuevos frameworks y componentes runtime requiere mucho tiempo. Hoy intentaremos facilitar el aprendizaje de algunas APIs populares MicroProfile para desarrolladores de Spring y mostraremos cómo utilizar simultáneamente las API de Spring y nuevas funcionalidades útiles. Quarkus.

Si nos adentramos un poco más, primero exploraremos el ámbito de aplicación y los detalles de cómo Quarkus soporta las interfaces API de Spring, para mostrar a los desarrolladores de Spring cómo pueden aplicar las APIs de MicroProfile en su trabajo diario. Luego hablaremos sobre las APIs de MicroProfile que serán útiles para los desarrolladores de Spring al crear microservicios.

¿Por qué Quarkus? En primer lugar, permite la codificación en vivo (live coding), es decir, la recarga automática de cualquier cambio en las APIs de MicroProfile, las APIs de Spring y otras APIs de Java, que se realiza con un solo comando: mvn quarkus:dev. En segundo lugar, el servicio que discutimos en nuestro ejemplo el servicio Person (que se compila desde las interfaces de API de Spring, MicroProfile y JPA en un archivo binario utilizando la imagen nativa de GraalVM) se inicia en solo 0.055 segundos y ocupa alrededor de 90 MB de RAM (RSS) en el punto final de una aplicación RESTful. Además, su compilación se lleva a cabo con un solo comando: mvn package -Pnative.

No profundizaremos en los detalles de MicroProfile, sino que intentaremos ayudar a los desarrolladores de Spring a comprender cómo se pueden utilizar las interfaces de API de Spring junto con las interfaces de API de MicroProfile en Quarkus.

Contenedores y Kubernetes

Para no sobrecargar este artículo, aquí examinaremos solo los aspectos de alto nivel del soporte Kubernetes, ya que es importante entender. Quarkus se posiciona como un stack de Java para Kubernetes, diseñado para minimizar el consumo de memoria y el tiempo de arranque de las aplicaciones y servicios Java, y, como resultado, aumentar la densidad de su despliegue en el host y reducir los costos generales.

Quarkus también soporta la autogeneración de recursos de Kubernetes y ofrece guías para el despliegue en plataformas Kubernetes y Red Hat OpenShift. Además, Quarkus genera automáticamente los archivos Dockerfile.jvm (empaquetado JVM) y Dockerfile.native (empaquetado binario nativo) necesarios para crear contenedores.

Y finalmente, al orientar Kubernetes como el entorno objetivo de despliegue, Quarkus no utiliza marcos de Java en los casos en que la funcionalidad equivalente se implementa a nivel de la propia plataforma Kubernetes. En la tabla 1 se presenta un mapa de correspondencia funcional entre Kubernetes y los marcos de Java típicos utilizados por los desarrolladores de Spring.

Tabla 1. Mapa de correspondencia funcional entre marcos de Java y Kubernetes.

Funcionalidad
Spring Boot tradicional
Kubernetes

Descubrimiento de servicios
Eureka
DNS

Configuración
Spring Cloud Config
Config Maps / Secrets

Balanceo de carga
Ribbon (del lado del cliente)
Servicio, Replication Controller (del lado del servidor)

Compilación y ejecución del código del ejemplo

En este artículo nos referimos a el ejemplo de proyecto, donde se utilizan conjuntamente las API de Spring y MicroProfile, y el mismo Java. El código de este ejemplo se puede compilar y ejecutar desde la línea de comandos; para más detalles, consulte el archivo README.md.

APIs del Spring Framework

Inyección de Dependencias

Quarkus admite toda una serie de APIs de Contextos e Inyección de Dependencias (CDI) y APIs de Inyección de Dependencias de Spring (Spring DI). Si trabaja con MicroProfile, Java EE y Jakarta EE, ya estará familiarizado con CDI. Por otro lado, los desarrolladores de Spring pueden usar la Extensión Quarkus para la API de Spring DI para asegurar la compatibilidad con Spring DI. Se presentan ejemplos de uso de las APIs de Spring DI compatibles en la tabla 2.

En en el proyecto de nuestro ejemplo se utiliza tanto CDI como Inyección de Dependencias de Spring. Se pueden encontrar más detalles y ejemplos sobre este tema en la guía de Quarkus titulada Guía de Spring DI.

Tabla 2. Ejemplos de uso de las APIs de Spring DI compatibles.

Funciones compatibles de Spring DI
Ejemplos

Inyección por Constructor

public PersonSpringController(
   PersonSpringRepository personRepository,  // inyectado      
   PersonSpringMPService personService) {    // inyectado
      this.personRepository = personRepository;
      this.personService = personService;
}

Inyección por Campo
Autowired
Value

@Autowired
@RestClient
SalutationRestClient salutationRestClient;

@Value("${fallbackSalutation}")
String fallbackSalutation;

Bean
@Configuration

@Configuration
public class AppConfiguration {
   @Bean(name = "capitalizeFunction")
   public StringFunction capitalizer() {
      return String::toUpperCase;
   }
}

Componente

@Component("noopFunction")
public class NoOpSingleStringFunction implements StringFunction {
   @Override
   public String apply(String s) {
      return s;
   }
}

Servicio

@Service
public class MessageProducer {
   @Value("${greeting.message}")
   String message;

   public String getPrefix() {
      return message;
   }
}

Marco web

A los usuarios de MicroProfile les gustará que Quarkus soporte JAX-RS, MicroProfile Rest Client, JSON-P y JSON-B como su modelo principal de programación web. Los desarrolladores de Spring estarán complacidos con la reciente adición del soporte para la Spring Web API en Quarkus, especialmente para las interfaces que manejan REST. Al igual que con la inyección de dependencias de Spring, el objetivo principal del soporte para la Spring Web API es que los desarrolladores de Spring puedan usar las interfaces de la Spring Web junto con las interfaces de MicroProfile. Los ejemplos de uso de las API de Spring Web soportadas se encuentran en la tabla 3, y más información y ejemplos sobre este tema pueden encontrarse en la guía de Quarkus llamada Guía de Spring Web.

Tabla 3. Ejemplos de uso de las API de Spring Web soportadas.

Funciones soportadas de Spring Web
Ejemplos

@RestController
@RequestMapping

@RestController
@RequestMapping("/person")
public class PersonSpringController {
   ...
   ...
   ...
}

@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@RequestParam
@RequestHeader
@MatrixVariable
@PathVariable
@CookieValue
@RequestBody
@ResponseStatus
@ExceptionHandler
@RestControllerAdvice (parcial)

@GetMapping(path = "/greet/{id}",
   produces = "text/plain")
   public String greetPerson(
   @PathVariable(name = "id") long id) {
   ...
   ...
   ...
}

Spring Data JPA

A los usuarios de MicroProfile también les agradará que Quarkus soporte JPA utilizando Hibernate ORM. También hay buenas noticias para los desarrolladores de Spring: Quarkus soporta las anotaciones y tipos comunes de Spring Data JPA. Los ejemplos de uso de las API de Spring Data JPA soportadas se encuentran en la tabla 4.
En en el proyecto de nuestro ejemplo se utilizan las API de Spring Data JPA, y más información está disponible en la guía de Quarkus titulada Guía de Spring Data JPA.

Tabla 4. Ejemplos de uso de las API de Spring Data JPA soportadas.

Funciones soportadas de Spring Data JPA
Ejemplos

CrudRepository

public interface PersonRepository
         extends JpaRepository,
                 PersonFragment {
   ...
}

Repositorio
JpaRepository
PagingAndSortingRepository

public class PersonRepository extends 

    Repository {

    Person save(Person entity);

    Optional findById(Person entity);
}

Fragmentos de Repositorio

public interface PersonRepository
         extends JpaRepository,
                 PersonFragment {
   ...
}

Métodos de consulta derivados

public interface PersonRepository extends CrudRepository {

    List findByName(String name);
    
    Person findByNameBySsn(String ssn);
    
    Optional 
       findByNameBySsnIgnoreCase(String ssn);

    Boolean existsBookByYearOfBirthBetween(
            Integer start, Integer end);
}

Consultas definidas por el usuario

public interface MovieRepository
         extends CrudRepository {

    Movie findFirstByOrderByDurationDesc();

    @Query("select m from Movie m where m.rating = ?1")
    Iterator findByRating(String rating);

    @Query("from Movie where title = ?1")
    Movie findByTitle(String title);
}

API de MicroProfile

Tolerancia a fallos

Las construcciones de tolerancia a fallos son muy importantes para prevenir fallos en cascada y crear arquitecturas de microservicios confiables. Los desarrolladores de Spring han estado utilizando durante años circuit-breakers para la tolerancia a fallos. Hystrix. Sin embargo, Hystrix no se ha actualizado desde hace tiempo, mientras que la tolerancia a fallos de MicroProfile está actualmente en desarrollo activo y cuenta con varios años de uso en producción. Por lo tanto, para aumentar la fiabilidad de los servicios en Quarkus, se recomienda utilizar las interfaces de API de MicroProfile Fault Tolerance, cuyos ejemplos de uso se presentan en la tabla 5. Puede encontrar información adicional sobre esto en la guía de Quarkus. Guía de Tolerancia a Fallos.

Tabla 5. Ejemplos de uso de las interfaces de API de MicroProfile Fault Tolerance soportadas.

Funciones de MicroProfile Fault Tolerance
Descripción
Ejemplos

@Asynchronous

Ejecución de lógica en un hilo separado

@Asynchronous
@Retry
public Future getSalutation() {
   ...
   return future;
}

@Bulkhead

Límite en la cantidad de solicitudes simultáneas

@Bulkhead(5)
public void fiveConcurrent() {
   makeRemoteCall(); //...
}

@CircuitBreaker

Manejo inteligente de fallos y recuperación de fallos

@CircuitBreaker(delay=500   // milisegundos
   failureRatio = .75,
   requestVolumeThreshold = 20,
   successThreshold = 5)
@Fallback(fallbackMethod = "fallback")
public String getSalutation() {
   makeRemoteCall(); //...
}

@Fallback

Llamado a lógica alternativa en caso de fallo

@Timeout(500) // milisegundos
@Fallback(fallbackMethod = "fallback")
public String getSalutation() {
   makeRemoteCall(); //...
}

public String fallback() {
   return "hello";
}

Retry

Reintento ante un fallo de solicitud

@Retry(maxRetries=3)
public String getSalutation() {
   makeRemoteCall(); //...
}

Timeout

Tiempo máximo de espera ante un fallo

@Timeout(value = 500) // milisegundos
@Fallback(fallbackMethod = "fallback")
public String getSalutation() {
   makeRemoteCall(); //...
}

Verificación de servicios (Service Health)

Las plataformas de Kubernetes monitorean la salud de los contenedores mediante servicios específicos. Para que la plataforma subyacente pueda monitorear los servicios, los desarrolladores de Spring suelen utilizar HealthIndicator personalizables y Spring Boot Actuator. En Quarkus, esto se puede lograr mediante MicroProfile Health, que por defecto realiza una verificación de operatividad (liveness check), aunque también se pueden configurar para verificar simultáneamente la operatividad y la preparación (readiness). Los ejemplos de uso de las API soportadas de MicroProfile Health se presentan en la tabla 6, y más información se proporciona en la guía de Quarkus. Guía de Salud.

Tabla 6. Ejemplos de uso de las interfaces de API de MicroProfile Health soportadas.

Funciones de MicroProfile Health
Descripción
Ejemplos

@Liveness

La plataforma reinicia aplicaciones contenedorizadas defectuosas
Endpoint:
host:8080/health/live

@Liveness
public class MyHC implements HealthCheck {
  public HealthCheckResponse call() {

   ...
   return HealthCheckResponse
     .named("myHCProbe")
     .status(ready ? true:false)
     .withData("mydata", data)
     .build();  
}

@Readiness

La plataforma no enviará tráfico a la aplicación containerizada si no está lista.
Endpoint:
host:8080/health/ready

@Readiness
public class MyHC implements HealthCheck {
  public HealthCheckResponse call() {

   ...
   return HealthCheckResponse
     .named("myHCProbe")
     .status(live ? true:false)
     .withData("mydata", data)
     .build();  
}

Métricas

Las aplicaciones proporcionan métricas ya sea para fines operativos (para monitorear los indicadores de rendimiento de SLA) o no operativos (indicadores comerciales de SLA). Los desarrolladores de Spring proporcionan métricas utilizando Spring Boot Actuator y Micrometer. A su vez, Quarkus utiliza MicroProfile Metrics para proporcionar métricas básicas (JVM y sistema operativo), métricas de proveedores (Quarkus) y métricas de aplicaciones. MicroProfile Metrics requiere que la implementación soporte los formatos de salida JSON y OpenMetrics (Prometheus). Ejemplos de uso de la API de MicroProfile Metrics se presentan en la tabla 7.

En en el proyecto de nuestro ejemplo Las métricas de MicroProfile se utilizan para proporcionar métricas de aplicación. Más información se puede encontrar en la guía de Quarkus. Guía de Métricas.

Tabla 7. Ejemplos de uso de las API de MicroProfile Metrics.

Funciones de MicroProfile Metrics
Descripción
Ejemplos

@Counted

Indica un contador que cuenta la cantidad de llamadas al objeto anotado.

@Counted(name = "fallbackCounter", 
  displayName = "Fallback Counter", 
  description = "Fallback Counter")
public String salutationFallback() {
   return fallbackSalutation;
}

@ConcurrentGauge

Indica un medidor que cuenta la cantidad de llamadas concurrentes al objeto anotado.

@ConcurrentGuage(
  name = "fallbackConcurrentGauge", 
  displayName="Fallback Concurrent", 
  description="Fallback Concurrent")
public String salutationFallback() {
   return fallbackSalutation;
}

@Gauge

Indica un medidor que mide el valor del objeto anotado.

@Metered(name = "FallbackGauge",
   displayName="Fallback Gauge",
   description="Fallback frequency")
public String salutationFallback() {
   return fallbackSalutation;
}

@Metered

Indica un medidor que rastrea la frecuencia de llamadas al objeto anotado.

@Metered(name = "MeteredFallback",
   displayName="Metered Fallback",
   description="Fallback frequency")
public String salutationFallback() {
   return fallbackSalutation;
}

Métrica

Anotación que contiene información sobre los metadatos al recibir una solicitud para agregar o producir una métrica.

@Metric
@Metered(name = "MeteredFallback",
   displayName="Metered Fallback",
   description="Fallback frequency")
public String salutationFallback() {
   return fallbackSalutation;
}

Temporal

Indica un temporizador que rastrea la duración del objeto anotado.

@Timed(name = "TimedFallback",
   displayName="Fallback de tiempo",
   description="Retraso de fallback")
public String salutationFallback() {
   return fallbackSalutation;
}

Puntos finales de métricas

Métricas de aplicaciones localhost:8080/metrics/application
Métricas básicas localhost:8080/metrics/base
Métricas del proveedor localhost:8080/metrics/vendor
Todas las métricas localhost:8080/metrics

Cliente REST de MicroProfile

Los microservicios suelen proporcionar puntos finales RESTful, para los cuales se requieren API de cliente adecuadas. Para utilizar estos puntos finales RESTful, los desarrolladores de Spring normalmente utilizan RestTemplate. Quarkus, por su parte, ofrece interfaces API de MicroProfile Rest Client, cuyos ejemplos de uso se muestran en la tabla 8.

En en el proyecto de nuestro ejemplo El uso de los puntos finales RESTful se realiza a través de MicroProfile Rest Client. Puede encontrar más información y ejemplos sobre este tema en la guía de Quarkus. Guía del cliente REST.

Tabla 8. Ejemplos de uso de las interfaces API de MicroProfile Rest Client.

Funciones del cliente REST de MicroProfile
Descripción
Ejemplos

@RegisterRestClient

Registra una interfaz Java tipificada como cliente REST

@RegisterRestClient
@Path("/")
public interface MyRestClient {
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getSalutation();
}

@RestClient

Marca la inyección de una instancia de la interfaz tipificada del cliente REST

@Autowired // o @Inject
@RestClient
MyRestClient restClient;

Invocación

Llama al punto final REST

System.out.println(
   restClient.getSalutation());

mp-rest/url

Define el punto final REST

application.properties:
org.example.MyRestClient/mp-rest/url=
   http://localhost:8081/myendpoint

Resultados

En este blog, que será especialmente útil para los desarrolladores de Spring, hemos explorado brevemente cómo utilizar las interfaces API de Spring junto con las interfaces de MicroProfile en Quarkus para desarrollar microservicios Java y luego compilarlos en un binario nativo que ahorra cientos de megabytes de memoria RAM y se inicia en cuestión de milisegundos.

Como ya habrás entendido, puede encontrar más información sobre el soporte para las API de Spring y MicroProfile, así como mucha otra información útil en las guías de Quarkus.

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster