Autowire MicroProfile Into Spring With Quarkus

When developing Java microservices, Eclipse MicroProfile and Spring Boot are often thought of as separate and distinct APIs. Developers default to their mental muscle memory by leveraging APIs they use on a daily basis. Learning new frameworks and runtimes can require a major time investment. This article aims to ease Spring developers’ introduction to some popular MicroProfile APIs by enabling them to use the Spring APIs they already know while benefiting from significant new capabilities offered by Quarkus.

More specifically, this article describes the scope, and some details, of the Spring APIs that Quarkus supports so Spring developers have a grasp of the foundation they can build on with MicroProfile APIs. The article then covers MicroProfile APIs that Spring developers will find helpful when developing microservices. Only a subset of MicroProfile APIs are covered. 

Why Quarkus? Live coding is one reason because any change is automatically reloaded whether you’re using MicroProfile, Spring, or a different Java API. Just run mvn quarkus:dev. That's it. A second compelling reason is because the example project's Person service, which compiles Spring, MicroProfile, and Java Persistence API (JPA) APIs into a native binary format, starts in 0.055 seconds, and uses approximately 90 MB of resident set size (RSS) RAM after reaching the application’s RESTful endpoints. Simply run mvn package -Pnative to compile to a native binary format. That's it.

This article does not go into detailed comparisons, but should help Spring developers understand how Spring and MicroProfile APIs can be combined with Quarkus.

Containers and Kubernetes

To keep length down, this article describes Kubernetes support only at a high level. But it is important to discuss. One of Quarkus’ key value propositions is "Kubernetes Native Java," where the goal is to minimize memory footprint and reduce startup time. The reduced memory footprint helps to increase the density of applications that share hardware, reducing overall costs.

Quarkus also supports auto-generation of Kubernetes resources, and guides for deploying Quarkus applications on Kubernetes and OpenShift are available. In addition, Dockerfile.jvm Java virtual machine (JVM) and Dockerfile.native native binary packages are automatically generated for container creation.

Last, given that Quarkus considers Kubernetes to be a target deployment environment, it forgoes using Java frameworks when inherent Kubernetes capabilities are available. Table 1 briefly maps the Java frameworks typically used by Spring developers to Kubernetes built-in capabilities.

Table 1: Java Framework to Kubernetes Mapping

Capability

Traditional Spring Boot

Kubernetes

Service discovery

Eureka

DNS

Configuration

Spring Cloud Config

ConfigMaps

Secrets

Load balancing

Ribbon (client side)

Service

ReplicationController

(server side)

Compiling and Running the Example Code

This article is accompanied by an example project that combines Spring and MicroProfile APIs in the same project and the same Java class. The code can be compiled and run from the command line. For instructions, see README.md.

Spring Framework APIs

This section describes dependency injection and the web framework for Spring Framework, including the Spring Data JPA and user-defined queries.

Dependency Injection

Quarkus supports many Contexts and Dependency Injection (CDI) and Spring Dependency Injection (DI) APIs. MicroProfile, Java EE, and Jakarta EE developers will be very familiar with CDI. Spring developers can use the Quarkus Extension for Spring DI API for Spring DI compatibility. Table 2 provides a sample of the supported Spring DI API features.

The example project uses CDI and Spring DI APIs. The Quarkus Spring DI Guide provides greater detail and additional examples.

Table 2: Sample of Supported Spring DI API Features

Supported Spring DI

Feature

Examples

Constructor Injection


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

Field Injection

@Autowired

@Value

 


@Autowired
@RestClient
SalutationMicroProfileRestClient 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 developers will be comfortable with Quarkus support for JAX-RS, MicroProfile Rest Client, JSON-P, and JSON-B as the core web programming model. Spring developers may be surprised to learn that Quarkus has recently added Spring Web API support, specifically around Spring REST-related APIs. As with Spring DI, the goal of Spring Web API support is to help Spring developers feel comfortable using Spring Web APIs and MicroProfile APIs together. Table 3 provides a sample of the supported Spring Web API features.

The example project uses Spring Web and MicroProfile Rest Client APIs. The Quarkus Spring Web Guide provides greater detail and additional examples.

Table 3: Sample of Supported Spring Web API Features

Supported Spring Web

Feature

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 developers will be comfortable with Quarkus JPA support using Hibernate Object Relational Mapping (ORM). Spring developers, have no fear! Quarkus supports commonly used Spring Data JPA annotations and types. Table 4 provides a sample of the supported Spring Data JPA API features. 

The example project uses Spring Data JPA repository APIs. The Quarkus Spring Data JPA Guide provides greater detail and additional examples.

Table 4: Sample of Supported Spring Data JPA API Features

Supported Spring Data JPA

Feature

Examples

CrudRepository


public interface PersonSpringRepository
    extends CrudRepository<Person, Long> {
        List<Person> findByAge(int age);
    }

Repository

JpaRepository

PagingAndSortingRepository

 


public class PersonRepository extends
    Repository<Person, Long> {
        Person save(Person entity);
        Optional<Person> findById(Person entity);
    }

Repository fragments


public interface PersonRepository extends JpaRepository<Person, Long>, PersonFragment {
    ...
}

Derived query methods

 

 


public interface PersonRepository extends CrudRepository<Person, Long> {
    List<Person> findByName(String name);
    Person findByNameBySsn(String ssn);
    Optional<Person>
    findByNameBySsnIgnoreCase(String ssn);
    Boolean existsBookByYearOfBirthBetween(Integer start, Integer end);
}

User-defined queries


public interface MovieRepository extends CrudRepository<Movie, Long> {
    Movie findFirstByOrderByDurationDesc();
    @Query("select m from Movie m where m.rating = ?1")
    Iterator<Movie> findByRating(String rating);
    @Query("from Movie where title = ?1")
    Movie findByTitle(String title);
}

MicroProfile APIs

This section describes the MicroProfile Fault Tolerance, Service Health, and Metrics APIs.

Fault Tolerance

Fault tolerance patterns are critical to prevent cascading failures and to create a reliable microservice architecture. Hystrix circuit-breaking has been a go-to fault tolerance pattern for Spring developers for quite a while. However, Hystrix is now in maintenance mode while the MicroProfile Fault Tolerance API is in active development and developers have been using it in production for years now. Quarkus recommends using MicroProfile Fault Tolerance APIs to improve service reliability. Table 5 provides a sample of the MicroProfile Fault Tolerance API features.

The example project uses the MicroProfile Fault Tolerance API, the @Timeout and @Fallback features in particular. The Quarkus Fault Tolerance Guide provides greater detail and additional examples.

Table 5: Sample of MicroProfile Fault Tolerance API Features

MicroProfile Fault Tolerance API

Feature

Description

Examples

@Asynchronous

Execute logic on a separate thread


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

@Bulkhead

Limit number of concurrent requests


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

@CircuitBreaker

Gracefully handle faults and fault recovery


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

@Fallback

Alternative logic called upon failure


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

@Retry

Retry a request


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

@Timeout

Wait period before assuming failure


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

Service Health

Platforms such as Kubernetes use probes to check container health. Spring developers use a custom HealthIndicator and Spring Boot Actuator to expose service health to the underlying platform. With Quarkus, Spring developers can use the MicroProfile Health API to expose service health. A default liveness check is provided, but developers can include custom liveness and readiness checks as well. Table 6 provides a sample of the MicroProfile Health API features.

The example project uses the MicroProfile Health API to expose application readiness. The Quarkus Health Guide provides greater detail and additional examples.

Table 6: Sample of MicroProfile Health API Features

MicroProfile Health

Feature

Description

Examples

@Liveness

Platform reboots unhealthy 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

Platform does not direct traffic to containerized applications that 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 expose metrics for operational reasons, such as performance service level agreements (SLAs), and non-operational reasons, such as business SLAs. Spring developers typically use Spring Boot Actuator and Micrometer to expose metrics. Quarkus uses MicroProfile Metrics to expose base (JVM and operating system), Vendor (Quarkus), and application metrics. The MicroProfile Metrics API requires implementations to support JavaScript Object Notation (JSON) and OpenMetrics (Prometheus) output formats. Table 7 provides a sample of the MicroProfile Metrics API features.

The example project uses the MicroProfile Metrics API to expose application metrics. The Quarkus Metrics Guide provides greater detail and additional examples.

Table 7: Sample of MicroProfile Metrics API Features

MicroProfile Metrics

Feature

Description

Examples

@Counted

Denotes a counter which counts the invocations of the annotated object


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

@ConcurrentGauge

 

Denotes a gauge which counts the parallel invocations of the annotated object


@ConcurrentGuage(

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

@Gauge

Denotes a gauge, which samples the

value of the annotated object

 


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

@Metered

Denotes a meter, which tracks the frequency of invocations of the annotated object


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

@Metric

An annotation that contains the metadata

information when requesting a metric to

be injected or produced


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

@Timed

 

Denotes a timer, which tracks duration of

the annotated object


@Timed(name = "TimedFallback",
    displayName="Timed Fallback",
    description="Time for fallback to complete")
public String salutationFallback() {
    return fallbackSalutation;
}

Metrics Endpoints

Application metrics

http://localhost:8080/metrics/application

Base metrics

http://localhost:8080/metrics/base

Vendor metrics

http://localhost:8080/metrics/vendor

All metrics

http://localhost:8080/metrics

MicroProfile Rest Client

Microservices often expose RESTful endpoints, requiring a client API to consume a RESTful endpoint. Spring developers typically use a RestTemplate to consume RESTful endpoints. Quarkus supports the MicroProfile Rest Client API to do the same. Table 8 provides a sample of MicroProfile Rest Client API features.

The example project uses the MicroProfile Rest Client API to consume RESTful endpoints. The Quarkus Rest Client Guide provides greater detail and additional examples.

Table 8: Sample of MicroProfile Rest Client API Features

MicroProfile

Rest Client

Feature

Description

Examples

@RegisterRestClient

Register a typed Java interface as a REST client


border="1"
        

@RestClient

Decorate instance injection of a typed REST client interface


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

Invocation

Invoke REST endpoint


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

mp-rest/url

Specify REST endpoint


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

Summary

This article provided an overview, primarily for Spring developers, of using Spring APIs and MicroProfile APIs with Quarkus. Spring developers can now use some of the APIs they know and love, along with MicroProfile APIs, to live-code Java microservices then compile them into a native binary format to save hundreds of megabytes of RAM while starting in milliseconds.

Note: Quarkus guides provide more detail about Spring and MicroProfile API support, and much, much more!

About the Author

John Clingan

John Clingan

Senior Principal Product Manager at Red Hat, Inc.