Quarkus – A New Age of Modern Java Frameworks is Here

If you’ve seen some of my talks, or read some of the articles, you probably already know that I’m not a big fan of frameworks in general – but I learned how to be good friends with them.

However, regardless of the fact if you like frameworks or not, Quarkus brings some worthwhile innovation to the table.

So, let’s ignore the cheesy “Supersonic Subatomic Java” line for a while, and let’s get down to the nitty-gritty, see main Quarkus features, and run a trivial hello-world application.

Quarkus Overview

One of the official elevator pitches states:

Quarkus is a Kubernetes Native Java framework tailored for GraalVM and HotSpot, crafted from best-of-breed Java libraries and standards.

Which sums it up pretty neatly. However, since Quarkus was build from scratch, it’s important to underline that it’s not constrained by backward compatibility which allowed it to fully embrace technologies like containerization or native images.

What’s more, it reuses widely-established standards like CDI, JAX-RS, JPA, JTA, etc. so no need to worry about relearning everything from scratch… again.

GraalVM Support

Thanks to the GraalVM compatibility, Quarkus achieves impressive startup times and RSS memory consumption.

Quarkus not only runs correctly on GraalVM but also embraces the integration by providing dedicated tooling.

If you want to generate a GraalVM native image, there’s no need to manually configure and maintain GraalVM distribution. You can simply supply an extra flag to Maven build and then let the plugin use a Dockerized GraalVM behind the scenes:

mvn package -Pnative -Dquarkus.native.container-build=true

That’s incredibly convenient.

What’s more, Quarkus provides an extension framework that makes GraalVM configuration a smooth experience for extensions creators. Making things GraalVM-compatible can be demanding, but luckily there’s quite an impressive list of already existing extensions.

If you want to see how it looks like, you can check out an extension I developed – quarkus-hazelcast-client.

Now, let’s have a look at some interesting Quarkus features.

Build-time Augmentation

Build-time augmentation is an extra build step used for processing metadata, config parsing, and any other logic that would normally be needed to perform at startup time. The resulting bytecode gets recorded and reused on the actual application startup.

Pushing as much as possible to build-time makes it possible to achieve impressive startup times, declutter memory, and in some cases to fail-fast before even running the application.

Hot-Reload

If you run your application using the mvn compile quarkus:dev incantation, it will restart seamlessly after detecting a change before serving an HTTP request. Thanks to the build-time augmentation, the whole reload often takes less than a second.

Docker-friendliness

Quarkus keeps all jar dependencies outside the main jar, which makes it possible to leverage Docker layer caching – if dependencies don’t change, the layer containing dependencies can be reused provided your Dockerfile is configured properly:

COPY target/lib/* /deployments/lib/ COPY target/*-runner.jar /deployments/app.jar

I bet now you’d like to try it out on your own – let’s try the above out in a small hello-world application.

Quickstart Guide

You can get started immediately by leveraging a predefined quarkus-maven-plugin task which generates a skeleton of the project for you (just like Maven archetypes do. However, this is not a classic Maven archetype):

mvn io.quarkus:quarkus-maven-plugin:1.2.1.Final:create \ -DprojectGroupId=com.pivovarit \ -DprojectArtifactId=quarkus-hello \ -DclassName="com.pivovarit.quarkus.HelloResource" \ -Dpath="/foo"

This gives us a baseline with a familiar structure.

You can find it on GitHub as well.

Besides the autogenerated hello-world application, we can notice a few nice touches like .dockerignore, .gitignore, and Docker image files which make our application Docker-ready since the beginning.

In order to give it a try, we can just type mvn compile quarkus:dev

The application starts in ~1s:

2020-02-23 10:53:09,541 INFO [io.quarkus] (main) quarkus-hello 1.0-SNAPSHOT (running on Quarkus 1.2.1.Final) started in 1.137s. Listening on: http://0.0.0.0:8080 2020-02-23 10:53:09,541 INFO [io.quarkus] (main) Profile dev activated. Live Coding activated. 2020-02-23 10:53:09,541 INFO [io.quarkus] (main) Installed features: [cdi, resteasy]

and is ready to accept requests:

> curl -X GET "localhost:8080/foo" hello%

However, here comes one of the Quarkus highlights.

Find the HelloResource class, change the return value to the value of your choice (I decided to move forward with “hello2”), then immediately issue another request.

> curl -X GET "localhost:8080/foo" hello2%

As you can see, you can witness the new value being returned immediately – Quarkus’ hot reload kicked in which allows you to stay in the flow while actively developing your application.

Meanwhile in the logs:

2020-02-23 10:57:43,278 INFO [io.qua.dev] (vert.x-worker-thread-0) Changed source files detected, recompiling (...) [unknown source]2020-02-23 10:57:43,665 INFO [io.quarkus] (vert.x-worker-thread-0) Quarkus stopped in 0.013s 2020-02-23 10:57:43,877 INFO [io.quarkus] (vert.x-worker-thread-0) quarkus-hello 1.0-SNAPSHOT (running on Quarkus 1.2.1.Final) started in 0.212s. Listening on: http://0.0.0.0:8080 2020-02-23 10:57:43,877 INFO [io.quarkus] (vert.x-worker-thread-0) Profile dev activated. Live Coding activated. 2020-02-23 10:57:43,877 INFO [io.quarkus] (vert.x-worker-thread-0) Installed features: [cdi, resteasy] 2020-02-23 10:57:43,877 INFO [io.qua.dev] (vert.x-worker-thread-0) Hot replace total time: 0.601s

However, if you want to ship your application, mvn package is your friend, and then you’re free to distribute a jar however you wish or containerize it.

Just don’t forget that Quarkus stores dependencies in a separate target/lib directory!

Running a Standalone Jar

mvn package java -jar target/quarkus-hello-1.0-SNAPSHOT-runner.jar

Running a Containerized Jar

mvn package docker build -f src/main/docker/Dockerfile.jvm -t pivovarit/quarkus-hello . docker run pivovarit/quarkus-hello

Running a Containerized Native Image

In order to build a native image, you don’t need to have GraalVM configured locally, Quarkus can use a dedicated containerized version of GraalVM for that:

mvn package -Pnative -Dquarkus.native.container-build=true docker build -f src/main/docker/Dockerfile.native -t pivovarit/quarkus-hello . docker run pivovarit/quarkus-hello

Enjoy your application starting in just a handful of milliseconds:

(... )INFO [io.quarkus] (main) quarkus-hello 1.0-SNAPSHOT (running on Quarkus 1.2.1.Final) started in 0.014s. Listening on: http://0.0.0.0:8080 (...) INFO [io.quarkus] (main) Profile prod activated. (...) INFO [io.quarkus] (main) Installed features: [cdi, resteasy]

Summary

Quarkus is a modern framework that fully embraces other modern technologies like containerization, build-time initialization, and GraalVM, and it’s definitely worth having it on the radar.

You can expect more Quarkus content soon.



