One of the hottest topics of 2019 Devoxx was Quarkus, a new Java framework from Red Hat. In a world dominated by Spring & JavaEE, the need for a new framework is not immediately obvious. Quarkus, however, is meant to solve several problems which are very real and not well addressed by frameworks we are used to. Based on how significant those problems are for you, Quarkus might be a very reasonable choice for your next project.

Quarkus, a new Java framework from Red Hat

Thanks to Kainos training policy, we had a chance to attend DevoxxPL conference in June 2019. Devoxx is held annually in Krakow and is the biggest Java conference in Poland. It is a perfect occasion to take a step back and evaluate your day-to-day practices & tooling against modern trends and learn new approaches to the problems that are an inherent part of software engineering.

One of the hottest topics of 2019 Devoxx was Quarkus, a new Java framework from Red Hat. In a world dominated by Spring & JavaEE, the need for a new framework is not immediately obvious. Quarkus, however, is meant to solve several problems which are very real and not well addressed by frameworks we are used to. Based on how significant those problems are for you, Quarkus might be a very reasonable choice for your next project.

Introduced by Red Hat in early 2019, Quarkus is Java framework with a goal to make Java a leading platform in Kubernetes and serverless. It is cleverly built on top of a number of popular Java libraries and, what is new in its approach, it integrates closely with GraalVM and OpenJDK. This second part – runtime integration – is the main point here.

Quarkus benefits

With the rise of Kubernetes and microservice architecture, some of Java shortcomings became more apparent. Especially, large memory consumption for every single service and long startup times are a fact of live with full-blown virtualization brought by JVM. There are of course lots of benefits that come with this abstraction, though (as opposed to programming for native executables) and those made Java and JVM the industry-leading standard.

Important step in bringing those two worlds closer has been brought by innovative virtual machine GraalVM, which makes it possible to compile Java code to a native executable. Resulting executables include a Substrate VM which brings a minimal set of runtime components needed to execute the code (think things like thread scheduler and garbage collector). Some of JVM features are not present or heavily-reduced (like reflection), but improvements in startup time and overhead memory reduction are real.

Quarkus does two things which push this even further. Firstly, it brings GraalVM closer to developers by abstracting some of the complexities and integrating GraalVM native compilation into the framework’s build toolchain, which basically should work out of the box with no additional hassle. This is a boon for those of us who don’t really have the time to deep-dive into GraalVM and experiment with native compilation setup. Secondly, development abstractions that are available for developer are carefully tailored in such a way that runtime requirements are minimized and as much execution as possible is being moved into compile-time phase. Part of this is compile time pre-boot, where bean initialization and dependency injection are done only once (during compile time), and your application is prepared to run before you start it. There is an interesting synergy between optimizations brought by GraalVM and Quarkus.

To give some background, Spring does build the context and performs injections after application start, and basically every time you run the application. Shifting context-building into compile time obviously has some limitations, and it makes it not possible to tamper with the context during runtime anymore. Also, injections need to be simple and cannot have any additional run-time logic. But once again, this brings further reduction in memory overhead and startup times as you are no longer carrying over all the mechanisms and work needed to prepare and maintain bean context into run-time.

For what it’s worth, Quarkus gives following numbers to illustrate how significant those reductions are altogether: a sample REST API application with database connection has ~30mb memory consumption and sub-second startup time. For a Spring application, that would be closer to 300mb and up to 10 seconds startup.

How Quarkus programming looks like?

First look at Quarkus code might be somehow surprising. Here is some basic REST controller:

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/hello")
public class GreetingResource {

    @Inject
    GreetingService service;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return service.getHello();
    }
}

This is pure JEE! Indeed, Quarkus does rely heavily on JEE standards, where possible. Most notably, its context management/DI features are a subset of Context and Dependency Injection (JEE CDI standard) which is usually provided and managed by the application server (with Quarkus you obviously don’t have application server). REST functionality is provided with JAX-RS bindings. Those design decisions to rely on standards might prove to be very beneficial as this approach should make adoption easier and minimize additional learning. Also, this might be possible to migrate existing applications that are already using JEE with little effort. I managed to find one story about such successful migration, but it came from Red Hat, and I wouldn’t rush with such decision myself.

One important thing to note here is that in order to achieve its goals, Quarkus implementation of mentioned standards is limited, i.e. some functionalities might be missing and some might have different semantics. Its features are carefully prepared to minimize startup time and run-time work, and this means that certain run-time features are deliberately omitted or simply not possible to provide. Some reading to get an understanding of differences with regard to the standard is definitely needed.

Quarkus comes with an impressive list of extensions. They are bindings to a number of specific popular technologies including Kafka, various databases, reactive web servers etc. Extensions also include many necessary tools like serialization libraries, OpenTracing implementation, logging, monitoring and many others. This gives the impression that Quarkus is a well though-out and ready-to-use product.

Why you would choose Quarkus?

Quarkus was developed with particular use cases in mind, i.e. Kubernetes and serverless. Both of those use cases benefit heavily from lower memory overhead and reduced startup time. In Kubernetes, high-availability and scaling are achieved by spawning additional short-lived instances to accommodate the load. Here, a short startup time increases efficiency and responsiveness significantly. Regarding serverless, Quarkus should reduce „cold start” problem (which is a significant blocker for Java serverless adoption) and allow to lower time and memory usage (for which you are billed for). For these specific areas, Quarkus could bring an order of magnitude improvements, so it is definitely worth checking out.

From the developer’s perspective, Quarkus seems like an obvious next step after GraalVM. It makes Graal more accessible by hiding some of its intricacies and providing an effortless way to create native executables. By tailoring application development features for compile time resolution, it allows to fully leverage native compilation and optimizations it brings and if you are already using GraalVM, Quarkus might bring further improvements.

One thing to bear in mind is that Quarkus is new with just a few months from its initial release. There is little info available at the moment, and drawbacks are not yet well known, but if Quarkus lives up to its promises, it might radically change how Java applications are developed and run.

Further reading: