Jak Quarkus łączy MicroProfile i Spring

Cześć wszystkim, z wami trzeci post z serii o Quarkus!

Jak Quarkus łączy MicroProfile i Spring

Podczas rozwoju mikrousług w Javie często uważa się, że Eclipse MicroProfile i Spring Boot to oddzielne i niezależne od siebie API. Domyślnie programiści zazwyczaj korzystają z tych API, do których są już przyzwyczajeni, ponieważ nauka nowych frameworków i komponentów runtime zajmuje dużo czasu. Dziś spróbujemy ułatwić opanowanie niektórych popularnych API MicroProfile dla programistów Spring i pokażemy, jak jednocześnie wykorzystać API Spring oraz nowe, przydatne możliwości Quarkus.

Jeśli przejdziemy nieco głębiej, najpierw omówimy obszar zastosowania i szczegóły dotyczące tego, jak Quarkus wspiera interfejsy API Spring, aby pokazać programistom Spring, jak mogą stosować API MicroProfile w swojej codziennej pracy. Następnie opowiemy o API MicroProfile, które będą przydatne programistom Spring w tworzeniu mikrousług.

Dlaczego akurat Quarkus? Po pierwsze, to kodowanie na żywo (live coding), czyli automatyczne przeładowanie wszelkich zmian w API MicroProfile, API Spring i innych API Javy, które wykonuje się jednym poleceniem: mvn quarkus:dev. Po drugie, omawiany w naszym przykładzie serwis Person (kompilowany z interfejsów API Spring, MicroProfile i JPA do pliku binarnego przy użyciu natywnego obrazu GraalVM) uruchamia się w zaledwie 0,055 sekundy i zajmuje około 90 MB pamięci RAM (RSS) na końcowym punkcie aplikacji RESTful. W dodatku jego kompilacja odbywa się przy pomocy jednego polecenia: mvn package -Pnative.

Nie będziemy zagłębiać się w szczegóły MicroProfile, a jedynie postaramy się pomóc programistom Spring zrozumieć, jak w Quarkus można używać interfejsów API Spring razem z interfejsami API MicroProfile.

Kontenery i Kubernetes

Aby nie przeciążać tego artykułu, omówimy tutaj jedynie ogólne aspekty wsparcia Kubernetes, co jest ważne do zrozumienia. Quarkus pozycjonuje się jako Java stack dla Kubernetes, ma na celu minimalizację zużycia pamięci i czasu uruchamiania aplikacji Java i usług, co z kolei zwiększa gęstość ich rozmieszczenia na hoście i obniża całkowite koszty.

Quarkus również wspiera autogenerację zasobów Kubernetes i oferuje przewodniki dotyczące wdrażania na platformach Kubernetes i Red Hat OpenShift. Ponadto Quarkus automatycznie generuje pliki Dockerfile.jvm (opakowanie JVM) i Dockerfile.native (opakowanie dla binariów natywnych), które są niezbędne do tworzenia kontenerów.

I wreszcie, bazując na Kubernetes jako docelowym środowisku wdrożeniowym, Quarkus nie używa frameworków Java w przypadkach, gdy podobna funkcjonalność jest wdrożona na poziomie samej platformy Kubernetes. W tabeli 1 przedstawiona jest mapa zgodności funkcjonalnej Kubernetes i typowych frameworków Java stosowanych przez deweloperów Spring.

Tabela 1. Mapa zgodności frameworków Java i Kubernetes.

Funkcjonalność
Tradycyjny Spring Boot
Kubernetes

Odkrywanie usług
Eureka
DNS

Konfiguracja
Spring Cloud Config
Config Maps / Secrets

Obciążenie równoważenie
Ribbon (po stronie klienta)
Usługa, Replication Controller (po stronie serwera)

Kompilacja i uruchomienie kodu z przykładu

W tym artykule odnosimy się do przykładu projektu, w którym współdzielone są interfejsy API Spring i MicroProfile, a nawet ten sam klas Java. Kod z tego przykładu można skompilować i uruchomić z linii poleceń, więcej informacji w pliku README.md.

Interfejsy API Spring Framework

Wstrzykiwanie zależności

Quarkus obsługuje szereg interfejsów API kontekstów i wstrzykiwania zależności (CDI) oraz interfejsów API Spring Dependency Injection (Spring DI). Jeśli pracujesz z MicroProfile, Java EE i Jakarta EE, to już dobrze znasz CDI. Z drugiej strony, deweloperzy Spring mogą używać Quarkus Extension for Spring DI API, aby zapewnić zgodność z Spring DI. Przykłady użycia wspieranych API Spring DI są przedstawione w tabeli 2.

W w projekcie z naszego przykładu zastosowano zarówno CDI, jak i Spring Dependency Injection. Dodatkowe informacje i przykłady na ten temat można znaleźć w przewodniku Quarkus zatytułowanym Spring DI Guide.

Tabela 2. Przykłady użycia wspieranych interfejsów API Spring DI.

Wspierane funkcje Spring DI
Przykłady

Wstrzykiwanie konstruktora

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

Wstrzykiwanie pola
@Autowired
@Value

@Autowired
@RestClient
SalutationRestClient salutationRestClient;

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

Ziarno
@Configuration

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

Komponent

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

Service

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

   public String getPrefix() {
      return message;
   }
}

Framework webowy

Użytkownikom MicroProfile spodoba się, że Quarkus obsługuje JAX-RS, MicroProfile Rest Client, JSON-P i JSON-B jako główny model programowania aplikacji webowych. Programiści Spring będą zadowoleni z nowo wprowadzonego wsparcia dla Spring Web API w Quarkus, w szczególności interfejsów odpowiedzialnych za REST. Podobnie jak w przypadku Spring DI, głównym celem wsparcia dla Spring Web API jest umożliwienie programistom Spring korzystania z interfejsów API Spring Web wraz z interfejsami API MicroProfile. Przykłady wykorzystania wspieranych interfejsów API Spring Web przedstawione są w tabeli 3, a dodatkowe informacje i przykłady można znaleźć w przewodniku Quarkus o nazwie Przewodnik po Spring Web.

Tabela 3. Przykłady zastosowania wspieranych interfejsów API Spring Web.

Obsługiwane funkcje Spring Web
Przykłady

@RestController
@RequestMapping

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

@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@RequestParam
@RequestHeader
@MatrixVariable
@PathVariable
@CookieValue
@RequestBody
@ResponseStatus
@ExceptionHandler
@RestControllerAdvice (częściowo)

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

Spring Data JPA

Użytkownikom MicroProfile również przypadnie do gustu, że Quarkus obsługuje JPA przy użyciu Hibernate ORM. Dla programistów Spring też jest dobra wiadomość: Quarkus obsługuje powszechnie stosowane adnotacje i typy Spring Data JPA. Przykłady użycia wspieranych interfejsów API Spring Data JPA przedstawione są w tabeli 4.
W w projekcie z naszego przykładu wspierane są interfejsy API Spring Data JPA, a dodatkowe informacje dostępne są w przewodniku Quarkus o nazwie Przewodnik po Spring Data JPA.

Tabela 4. Przykłady zastosowania wspieranych interfejsów API Spring Data JPA.

Obsługiwane funkcje Spring Data JPA
Przykłady

CrudRepository

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

Repozytorium
JpaRepository
PagingAndSortingRepository

public class PersonRepository extends 

    Repository {

    Person save(Person entity);

    Optional findById(Person entity);
}

Fragmenty repozytoriów

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

Metody zapytań pochodnych

public interface PersonRepository extends CrudRepository {

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

    Boolean existsBookByYearOfBirthBetween(
            Integer start, Integer end);
}

Zapytania zdefiniowane przez użytkownika

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);
}

Interfejsy API MicroProfile

Tolerancja na błędy (Fault tolerance)

Konstrukcje wysokiej dostępności są bardzo ważne, aby zapobiegać awariom kaskadowym i tworzyć niezawodne architektury mikroserwisowe. Programiści Spring od lat korzystają z circuit-breaker'ów w celu zapewnienia odporności na awarie. Hystrix. Jednak Hystrix od dłuższego czasu nie był aktualizowany, a API MicroProfile Fault Tolerance jest aktywnie rozwijane i ma już za sobą kilka lat użytkowania w produkcji. Dlatego w celu zwiększenia niezawodności usług w Quarkus zaleca się korzystanie z interfejsów API MicroProfile Fault Tolerance, a przykłady ich użycia są przedstawione w tabeli 5. Dodatkowe informacje można znaleźć w przewodniku Quarkus. Przewodnik po wysokiej dostępności.

Tabela 5. Przykłady użycia obsługiwanych interfejsów API MicroProfile Fault Tolerance.

Funkcje MicroProfile Fault Tolerance
Opis
Przykłady

@Asynchronous

Wykonywanie logiki w osobnym wątku

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

@Bulkhead

Ograniczenie liczby jednoczesnych żądań

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

@CircuitBreaker

Inteligentne przetwarzanie błędów i odzyskiwanie po awariach

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

@Fallback

Wywołanie alternatywnej logiki w przypadku awarii

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

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

Retry

Powtórzenie w przypadku awarii żądania

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

Timeout

Czas oczekiwania w przypadku awarii

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

Sprawdzanie stanu usług (Service Health)

Platformy Kubernetes monitorują stan kontenerów za pomocą specjalnych usług. Aby dolna platforma mogła monitorować usługi, programiści Spring zazwyczaj korzystają z konfigurowalnych HealthIndicator i Spring Boot Actuator. W Quarkus można to zrealizować za pomocą MicroProfile Health, które domyślnie wykonują sprawdzenie stanu (liveness check), ale mogą być także skonfigurowane do jednoczesnego sprawdzania liveness i readiness (gotowości). Przykłady użycia obsługiwanych interfejsów API MicroProfile Health przedstawione są w tabeli 6, a dodatkowe informacje zawarte są w przewodniku Quarkus. Przewodnik po zdrowiu.

Tabela 6. Przykłady użycia obsługiwanych interfejsów API MicroProfile Health.

Funkcje MicroProfile Health
Opis
Przykłady

@Liveness

Platforma przeprowadza ponowne uruchomienie uszkodzonych aplikacji kontenerowych
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

Platforma nie będzie kierować ruchu do kontenerizowanej aplikacji, jeśli będzie ona niegotowa
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();  
}

Metryki

Aplikacje dostarczają metryki zarówno w celach operacyjnych (do monitorowania wskaźników wydajności SLA), jak i nieoperacyjnych (wskaźniki biznesowe SLA). Programiści Spring dostarczają metryki za pomocą Spring Boot Actuator i Micrometer. Z kolei Quarkus wykorzystuje MicroProfile Metrics do dostarczania podstawowych metryk (JVM i system operacyjny), metryk dostawców (Quarkus) i metryk aplikacji. MicroProfile Metrics wymaga, aby implementacja wspierała formaty wyjściowe JSON i OpenMetrics (Prometheus). Przykłady użycia API MicroProfile Metrics są podane w tabeli 7.

W w projekcie z naszego przykładu MicroProfile Metrics są używane do dostarczania metryk aplikacji. Dalsze informacje można znaleźć w przewodniku Quarkus Przewodnik po metrykach.

Tabela 7. Przykłady użycia interfejsów API MicroProfile Metrics.

Funkcje MicroProfile Metrics
Opis
Przykłady

@Counted

Oznacza licznik, który zlicza liczbę wywołań oznaczonego obiektu

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

@ConcurrentGauge

Oznacza wskaźnik, który zlicza liczbę równoległych wywołań oznaczonego obiektu

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

@Gauge

Oznacza wskaźnik, który mierzy wartość oznaczonego obiektu

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

@Metered

Oznacza wskaźnik, który śledzi częstotliwość wywołań oznaczonego obiektu

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

Metryka

Adnotacja zawierająca informacje o metadanych, w momencie zapytania o utworzenie lub produkcję metryki

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

Czasowany

Oznacza timer, który śledzi czas trwania oznaczonego obiektu

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

Punkty końcowe metryk

Metryki aplikacji localhost:8080/metrics/application
Podstawowe metryki localhost:8080/metrics/base
Metryki dostawcy localhost:8080/metrics/vendor
Wszystkie metryki localhost:8080/metrics

Klient REST MicroProfile

Mikroserwisy często udostępniają punkty końcowe RESTful, do których obługi wymagane są odpowiednie API klientów. Aby korzystać z punktów końcowych RESTful, deweloperzy Springa zazwyczaj używają RestTemplate. Quarkus oferuje jednak API MicroProfile Rest Client do tego celu, a przykłady jego użycia podano w tabeli 8.

W w projekcie z naszego przykładu Użycie punktów końcowych RESTful jest realizowane za pomocą MicroProfile Rest Client. Dodatkowe informacje i przykłady na ten temat można znaleźć w przewodniku Quarkus. Przewodnik klienta REST.

Tabela 8. Przykłady użycia API MicroProfile Rest Client.

Funkcje MicroProfile Rest Client
Opis
Przykłady

@RegisterRestClient

Rejestruje typizowany interfejs Java jako klienta REST

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

@RestClient

Oznacza wstrzyknięcie instancji typizowanego interfejsu klienta REST

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

Wywołanie

Wywołuje punkt końcowy REST

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

mp-rest/url

Ustala punkt końcowy REST

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

Podsumowanie

W tym blogu, który przede wszystkim będzie przydatny dla deweloperów Springa, krótko omówiliśmy, jak w Quarkus używać interfejsów API Springa razem z API MicroProfile do tworzenia mikroserwisów Java, a następnie kompilować je do natywnego kodu binarnego, co oszczędza setki megabajtów pamięci RAM i uruchamia się w kilka milisekund.

Jak już zrozumieliście, dodatkowe informacje o wsparciu dla interfejsów API Spring i MicroProfile oraz wiele innych przydatnych informacji można znaleźć w przewodnikach Quarkus.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster