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

When developing Java microservices, it is often considered that and 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 and show how to simultaneously leverage Spring APIs and new useful features. .
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 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 , 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 of Kubernetes resources and offers 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 , 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 and Spring Dependency Injection (Spring DI) APIs. If you are working with MicroProfile, , 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 utilizes both CDI and Spring Dependency Injection. More information and examples on this topic can be found in the Quarkus guide titled .
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
@RestClient
SalutationRestClient salutationRestClient;
@Value("${fallbackSalutation}")
String fallbackSalutation;
@Configuration
@Configuration
public class AppConfiguration {
@Bean(name = "capitalizeFunction")
public StringFunction capitalizer() {
return String::toUpperCase;
}
}
@Component("noopFunction")
public class NoOpSingleStringFunction implements StringFunction {
@Override
public String apply(String s) {
return s;
}
}
@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 .
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 Spring Data JPA APIs are used, and additional information is available in the Quarkus guide titled .
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. . 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. .
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 on request failure
@Retry(maxRetries=3)
public String getSalutation() {
makeRemoteCall(); //...
}
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. .
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 MicroProfile Metrics are used to provide application metrics. For more information, refer to the Quarkus 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;
}
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;
}
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 :8080/metrics/application
Basic Metrics :8080/metrics/base
Vendor Metrics :8080/metrics/vendor
All Metrics :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 Using RESTful endpoints is done via the MicroProfile REST Client. For more information and examples, please refer to the Quarkus 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 .
Source: habr.com
