How Quarkus Combines MicroProfile and Spring

Hello everyone, and welcome to the third post in our series about Quarkus!

How Quarkus Combines MicroProfile and Spring

When developing Java microservices, it is often considered that Eclipse MicroProfile and Spring Boot are separate and independent APIs from each other. Typically, programmers tend to use the APIs they are already familiar with, as learning new frameworks and runtime components takes time. Today we will try to simplify the learning of some popular MicroProfile APIs for Spring developers and show how to simultaneously leverage Spring APIs and new useful features. Quarkus.

To elaborate, we will first look at the use cases and details of how Quarkus supports Spring APIs to demonstrate to Spring developers how MicroProfile APIs can be applied in their daily work. Then we will discuss the MicroProfile APIs that will be useful for Spring developers when creating microservices.

Why Quarkus? Firstly, it supports live coding, meaning any changes made to the MicroProfile APIs, Spring APIs, and other Java APIs are automatically reloaded with just one command: mvn quarkus:dev. Secondly, the service described in our example the Person service (which compiles from Spring, MicroProfile, and JPA APIs into a binary file using the GraalVM native image) starts in just 0.055 seconds and consumes about 90 MB of RAM (RSS) at the RESTful application's endpoint. The compilation itself is completed with a single command: mvn package -Pnative.

We will not delve into the details of MicroProfile but will strive to help Spring developers understand how Spring APIs can be used along with MicroProfile APIs in Quarkus.

Containers and Kubernetes

To avoid overwhelming this article, we will only consider high-level aspects of support Kubernetes, as it's important to understand. Quarkus is positioned as a Java stack for Kubernetes, designed to minimize memory usage and startup time for Java applications and services, thereby increasing their density on the host and reducing overall costs.

Quarkus also supports auto-generation of Kubernetes resources and offers guides for deployment on Kubernetes and Red Hat OpenShift platforms. Additionally, Quarkus automatically generates Dockerfile.jvm (JVM packaging) and Dockerfile.native (native binary packaging) files necessary for container creation.

Finally, focusing on Kubernetes as the target deployment environment, Quarkus does not use Java frameworks where equivalent functionality is realized at the Kubernetes platform level. Table 1 presents a mapping of functional equivalence between Kubernetes and typical Java frameworks used by Spring developers.

Table 1. Mapping of functional equivalence between Java frameworks and Kubernetes.

Functionality
Traditional Spring Boot
Kubernetes

Service discovery
Eureka
DNS

Configuration
Spring Cloud Config
Config Maps / Secrets

Load Balancing
Ribbon (client-side)
Service, Replication Controller (server-side)

Compiling and running the example code

In this article, we refer to the project example, where the Spring and MicroProfile APIs are used together, along with the very same Java class. The code from this example can be compiled and run from the command line; for more details, see the README.md file.

Spring Framework APIs

Dependency Injection

Quarkus supports a wide range of Contexts and Dependency Injection (CDI) APIs and Spring Dependency Injection (Spring DI) APIs. If you are working with MicroProfile, Java EE and Jakarta EE, you are likely familiar with CDI. On the other hand, Spring developers can use the Quarkus Extension for Spring DI API for compatibility with Spring DI. Examples of using supported Spring DI APIs are provided in Table 2.

In the project from our example utilizes both CDI and Spring Dependency Injection. More information and examples on this topic can be found in the Quarkus guide titled Spring DI Guide.

Table 2. Examples of using supported Spring DI APIs.

Supported Spring DI features
Examples

Constructor Injection

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

Field Injection
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;
   }
}

Component

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

Web framework

MicroProfile users will appreciate that Quarkus supports JAX-RS, MicroProfile Rest Client, JSON-P, and JSON-B as the primary web programming model. Spring developers will be pleased with the recently added support for Spring Web API in Quarkus, particularly interfaces responsible for REST. Similar to Spring DI, the main goal of supporting Spring Web API is to allow Spring developers to use Spring Web interfaces alongside MicroProfile interfaces. Examples of using supported Spring Web APIs are provided in Table 3, and additional information and examples on this topic can be found in the Quarkus guide titled Spring Web Guide.

Table 3. Examples of using supported Spring Web API interfaces.

Supported Spring Web Features
Examples

@RestController
@RequestMapping

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

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

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

Spring Data JPA

MicroProfile users will also be pleased that Quarkus supports JPA using Hibernate ORM. Spring developers have good news as well: Quarkus supports standard annotations and types from Spring Data JPA. Examples of using supported Spring Data JPA APIs are provided in Table 4.
In the project from our example Spring Data JPA APIs are used, and additional information is available in the Quarkus guide titled Spring Data JPA Guide.

Table 4. Examples of using supported Spring Data JPA API interfaces.

Supported Spring Data JPA Features
Examples

CrudRepository

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

Repository
JpaRepository
PagingAndSortingRepository

public class PersonRepository extends 

    Repository {

    Person save(Person entity);

    Optional findById(Person entity);
}

Repository Fragments

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

Derived query methods

public interface PersonRepository extends CrudRepository {

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

    Boolean existsBookByYearOfBirthBetween(
            Integer start, Integer end);
}

User-defined queries

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

MicroProfile APIs

Fault tolerance

Fault tolerance constructs are crucial for preventing cascading failures and creating reliable microservices architectures. Spring developers have been using circuit breakers for fault tolerance for many years. Hystrix. However, Hystrix has not been updated for a long time, while the MicroProfile Fault Tolerance is actively being developed and has several years of production use behind it. Therefore, to enhance service reliability in Quarkus, it is recommended to use the MicroProfile Fault Tolerance APIs, with usage examples provided in Table 5. Additional information can be found in the Quarkus guide. Fault Tolerance Guide.

Table 5. Examples of using supported MicroProfile Fault Tolerance APIs.

MicroProfile Fault Tolerance Features
Description
Examples

@Asynchronous

Execution of logic in a separate thread

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

@Bulkhead

Limiting the number of concurrent requests

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

@CircuitBreaker

Intelligent failure handling and recovery from failures

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

@Fallback

Invoking alternative logic in case of failure

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

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

Retry

Retry on request failure

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

Timeout

Control time limit on failure

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

Service Health Check

Kubernetes platforms monitor the health of containers using special services. For the underlying platform to monitor services, Spring developers typically use customizable HealthIndicator and Spring Boot Actuator. In Quarkus, this can be done with MicroProfile Health, which by default performs liveness checks but can also be configured to check both liveness and readiness simultaneously. Examples of using supported MicroProfile Health APIs are provided in Table 6, and additional information is presented in the Quarkus guide. Health Guide.

Table 6. Examples of using supported MicroProfile Health APIs.

MicroProfile Health Features
Description
Examples

@Liveness

The platform performs a restart of faulty containerized applications
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

The platform will not route traffic to containerized applications if they are not ready.
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();  
}

Metrics

Applications provide metrics either for operational purposes (to monitor SLA performance indicators) or for non-operational ones (business SLA metrics). Spring developers provide metrics using Spring Boot Actuator and Micrometer. Quarkus, on the other hand, uses MicroProfile Metrics to provide basic metrics (JVM and operating system), vendor metrics (Quarkus), and application metrics. MicroProfile Metrics requires implementations to support output formats in JSON and OpenMetrics (Prometheus). Examples of using the MicroProfile Metrics API are provided in Table 7.

In the project from our example MicroProfile Metrics are used to provide application metrics. For more information, refer to the Quarkus guide. Metrics Guide.

Table 7. Examples of using the MicroProfile Metrics APIs.

MicroProfile Metrics Features
Description
Examples

@Counted

Indicates a counter that counts the number of invocations of the annotated object.

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

@ConcurrentGauge

Indicates a gauge that counts the number of concurrent invocations of the annotated object.

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

@Gauge

Indicates a gauge that measures the value of the annotated object.

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

@Metered

Indicates a meter that tracks the frequency of invocations of the annotated object.

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

Metric

Annotation that contains metadata information upon receiving a request to create or produce a metric.

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

Timed

Indicates a timer that tracks the duration of the annotated object.

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

Metrics Endpoints

Application Metrics localhost:8080/metrics/application
Basic Metrics localhost:8080/metrics/base
Vendor Metrics localhost:8080/metrics/vendor
All Metrics localhost:8080/metrics

MicroProfile REST Client

Microservices often provide RESTful endpoints, which require corresponding client APIs to interact with. Spring developers typically use RestTemplate for this purpose. In contrast, Quarkus offers MicroProfile REST Client APIs to address this need, with usage examples provided in Table 8.

In the project from our example Using RESTful endpoints is done via the MicroProfile REST Client. For more information and examples, please refer to the Quarkus guide. Rest Client Guide.

Table 8. Examples of using MicroProfile REST Client APIs.

Features of MicroProfile REST Client
Description
Examples

@RegisterRestClient

Registers a typed Java interface as a REST client

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

@RestClient

Marks an instance of a typed REST client interface for dependency injection

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

Invocation

Invokes the REST endpoint

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

mp-rest/url

Sets the REST endpoint

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

Summary

In this blog, primarily useful for Spring developers, we briefly examined how to use Spring APIs alongside MicroProfile APIs in Quarkus to develop Java microservices and then compile them into native binary code that saves hundreds of megabytes of memory and starts in mere milliseconds.

As you may have understood, more information on the support for Spring and MicroProfile APIs, as well as a wealth of other useful information, can be found in Quarkus Guides.

Source: habr.com

Buy reliable website hosting with DDoS protection, VPS VDS servers 🔥 Buy reliable website hosting with DDoS protection, VPS VDS servers | ProHoster