How Quarkus Integrates MicroProfile and Spring

Hello everyone, and with you the third post from the Quarkus series!

When developing Java microservices, it is often believed that Eclipse MicroProfile and Spring boot – These are separate and independent of each other APIs. By default, programmers typically use the APIs they are used to, since learning new frameworks and runtime components takes a lot of time. Today we will try to simplify the development of some popular MicroProfile API for Spring Developers and show how to simultaneously use the Spring API and new useful features Quarkus.

If a little more detailed, we will first look at the scope and details of how Quarkus supports Spring APIs to show Spring developers how to use the MicroProfile API in their daily work. Then we will talk about the MicroProfile API, which will be useful for Spring developers when creating microservices.

Why Quarkus? Firstly, this is live coding, that is, automatic reloading of any changes to the MicroProfile API, Spring API and other Java APIs, which is performed with just one command: mvn quarkus: dev. Secondly, considered in our example the Person service (it is compiled from the Spring, MicroProfile, and JPA APIs into a binary file using the native GraalVM image) starts in just 0.055 seconds and takes about 90 MB of RAM (RSS) at the endpoint of the RESTful application. Moreover, its compilation itself is performed with just one command: mvn package -Pnative.

We will not go into the details of MicroProfile, but only try to help Spring developers understand how in Quarkus you can use Spring APIs along with MicroProfile APIs.

Containers and Kubernetes

In order not to overload this article, we will consider here only the high-level aspects of support Kubernetesbecause it is important to understand. Quarkus is positioned as a Java stack for Kubernetes, it is designed to minimize memory consumption and startup time of Java applications and services, and, as a result, increase the density of their placement on the host and reduce overall costs.

Quarkus also supports auto-generation Kubernetes resources and offers guides Deployment on Kubernetes and Red Hat OpenShift Platforms In addition, Quarkus automatically generates the Dockerfile.jvm (JVM packaging) and Dockerfile.native (native binary packaging) files needed to create containers.

Finally, focusing on Kubernetes as the target deployment environment, Quarkus does not use Java frameworks in cases where similar functionality is implemented at the level of the Kubernetes platform itself. Table 1 shows a map of the functional correspondence of Kubernetes and the typical Java frameworks used by Spring developers.

Table 1. Functional mapping map for Java frameworks and Kubernetes.

FunctionalTraditional Spring BootKubernetes
Service discoveryEurekaDNS
ConfigurationSpring cloud configConfig Maps / Secrets
Load balancingRibbon (client side)Service, Replication Controller (server side)

Compiling and running the code from the example

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

Spring Framework APIs

Dependency injection

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

IN project from our example used by both CDI and Spring Dependency Injection. For more information and examples on this topic, see the Quarkus manual, called Spring DI Guide.

Table 2. Examples of using the supported Spring DI APIs.

Supported Spring DI FeaturesExamples
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 enjoy Quarkus supporting JAX-RS, MicroProfile Rest Client, JSON-P and JSON-B as their primary web programming model. Spring developers will be pleased with the recent support of the Spring Web API in Quarkus, in particular, the REST interfaces. By analogy with Spring DI, the main goal of supporting the Spring Web API is for Spring developers to use the Spring Web APIs along with the MicroProfile APIs. Examples of use of the supported Spring Web APIs are given in Table 3, and additional information and examples on this topic can be found in the Quarkus manual, which is called Spring web guide.

Table 3. Examples of using the supported Spring Web APIs.

Supported Spring Web FeaturesExamples
@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 like Quarkus to support JPA using Hibernate ORM. There’s some good news for Spring developers too: Quarkus supports common annotations and Spring Data JPA types. Examples of using the supported Spring Data JPA APIs are shown in Table 4.
IN project from our example uses the Spring Data JPA APIs, and more information is available in the Quarkus tutorial called Spring Data JPA Guide.

Table 4. Examples of use of the supported Spring Data JPA APIs.

Supported Spring Data JPA FeaturesExamples
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 designs are critical to preventing cascading failures and building robust microservice 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, but MicroProfile’s Fault Tolerance is now actively developing and has already had several years of production use. Therefore, to increase the reliability of services in Quarkus, it is recommended to use the MicroProfile Fault Tolerance APIs, examples of which are given in Table 5. For more information about this, see the Quarkus manual. Fault Tolerance Guide.

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

MicroProfile Fault Tolerance FeaturesDescriptionExamples
@AsynchronousRunning logic in a separate thread
@Asynchronous
@Retry
public Future getSalutation() {
   ...
   return future;
}
@BulkheadLimit the number of concurrent requests
@Bulkhead(5)
public void fiveConcurrent() {
   makeRemoteCall(); //...
}
@CircuitBreakerSmart crash management and crash recovery
@CircuitBreaker(delay=500   // milliseconds
   failureRatio = .75,
   requestVolumeThreshold = 20,
   successThreshold = 5)
@Fallback(fallbackMethod = "fallback")
public String getSalutation() {
   makeRemoteCall(); //...
}
@FallbackAlternative logic call in case of failure
@Timeout(500) // milliseconds
@Fallback(fallbackMethod = "fallback")
public String getSalutation() {
   makeRemoteCall(); //...
}

public String fallback() {
   return "hello";
}
RetryRetry on request failure
@Retry(maxRetries=3)
public String getSalutation() {
   makeRemoteCall(); //...
}
TimeoutFailure Timeout
@Timeout(value = 500 )   // milliseconds
@Fallback(fallbackMethod = "fallback")
public String getSalutation() {
   makeRemoteCall(); //...
}

Service Check (Service Health)

Kubernetes platforms monitor container health using special services. So that the underlying platform can monitor services, Spring developers usually use the customizable HealthIndicator and Spring Boot Actuator. In Quarkus, this can be done using MicroProfile Health, which by default perform a liveness check, but can be configured to simultaneously check liveness and readiness. Examples of using the supported MicroProfile Health APIs are shown in Table 6, and more information is provided in the Quarkus Guide Health guide.

Table 6. Examples of use of the supported MicroProfile Health APIs.

MicroProfile Health FeaturesDescriptionExamples
@LivenessPlatform reloads failed 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();  
}
@ReadinessThe platform will not send traffic to containerized applications if it is 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 non-operational (business SLA indicators). Spring developers provide metrics using the Spring Boot Actuator and Micrometer. In turn, Quarkus uses MicroProfile Metrics to provide basic metrics (JVM and operating system), vendor metrics (Quarkus), and application metrics. MicroProfile Metrics requires that the implementation support JSON and OpenMetrics (Prometheus) output formats. Examples of using the MicroProfile Metrics API are shown in Table 7.

IN project from our example MicroProfile Metrics are used to provide application metrics. For more information, see the Quarkus manual. Metrics guide.

Table 7. MicroProfile Metrics API Usage Examples.

MicroProfile Metrics FeaturesDescriptionExamples
@CountedIndicates a counter that counts the number of calls to an annotated object.
@Counted(name = "fallbackCounter", 
  displayName = "Fallback Counter", 
  description = "Fallback Counter")
public String salutationFallback() {
   return fallbackSalutation;
}
@ConcurrentGaugeIndicates a gauge sensor that counts the number of parallel calls of an annotated object
@ConcurrentGuage(
  name = "fallbackConcurrentGauge", 
  displayName="Fallback Concurrent", 
  description="Fallback Concurrent")
public String salutationFallback() {
   return fallbackSalutation;
}
@GaugeIndicates a gauge that measures the value of an annotated object.
@Metered(name = "FallbackGauge",
   displayName="Fallback Gauge",
   description="Fallback frequency")
public String salutationFallback() {
   return fallbackSalutation;
}
@MeteredIndicates a meter that monitors the frequency of calling an annotated object.
@Metered(name = "MeteredFallback",
   displayName="Metered Fallback",
   description="Fallback frequency")
public String salutationFallback() {
   return fallbackSalutation;
}
MetricAn annotation containing information about metadata when a request is made to enter or produce a metric
@Metric
@Metered(name = "MeteredFallback",
   displayName="Metered Fallback",
   description="Fallback frequency")
public String salutationFallback() {
   return fallbackSalutation;
}
TimedIndicates a timer that tracks the duration of an 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 that require appropriate client APIs. To use RESTful endpoints, Spring developers typically use a RestTemplate. Quarkus also offers MicroProfile Rest Client APIs to solve this problem, examples of which are given in Table 8.

IN project from our example RESTful endpoints are used with the MicroProfile Rest Client. Further information and examples on this topic can be found in the Quarkus manual. Rest Client Guide.

Table 8. Examples of using the MicroProfile Rest Client APIs.

MicroProfile Rest Client FeaturesDescriptionExamples
@RegisterRestClientRegisters a typed Java interface as a REST client
@RegisterRestClient
@Path("/")
public interface MyRestClient {
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getSalutation();
}
@RestClientMarks the implementation of an instance of a typed REST client interface
@Autowired // or @Inject
@RestClient
MyRestClient restClient;
InvocationInvokes a REST endpoint
System.out.println(
   restClient.getSalutation());
mp-rest / urlSpecifies a REST endpoint
application.properties:
org.example.MyRestClient/mp-rest/url=
   http://localhost:8081/myendpoint

Summary

In this blog, which is primarily useful for Spring developers, we briefly looked at how to use Spring APIs in Quarkus together with MicroProfile APIs to develop Java microservices and then compile them into native binary code, which saves hundreds of megabytes of RAM and starts in a matter of milliseconds.

As you already understood, additional information on support for the Spring and MicroProfile APIs, as well as a host of other useful information, can be found in Quarkus Guides.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *