The pro­gram­ming language Java is known as a long-es­tab­lished “industry language”. It was created in the early years of the Internet, but the web has developed rapidly since then. In addition to classic client-server ar­chi­tec­ture, there are a number of exciting al­ter­na­tive models: container-based ap­pli­ca­tions, mi­croser­vices, server­less computing, and reactive web apps have es­tab­lished them­selves in the main­stream. These types of ap­pli­ca­tions have been difficult to implement with Java. With the Quarkus framework, that’s about to change. RedHat manager Ken Johnson put it this way:

Quote

“… it’s a very small Java stack, perfect for con­tain­ers, server­less and other scenarios where you’re running Java ap­pli­ca­tions in the cloud.”

– Ken Johnson, Source: https://www.openshift.com/blog/quarks-is-here-for-your-java

We will introduce you to Quarkus and show you how this framework is rev­o­lu­tion­iz­ing the creation of Java ap­pli­ca­tions.

What makes Quarkus special?

Quarkus is a framework developed by RedHat for creating Java ap­pli­ca­tions. Quarkus was developed with the goal of running Java programs in con­tain­ers. In par­tic­u­lar, it focuses on sup­port­ing or­ches­tra­tion software Ku­ber­netes. Another focus of Quarkus de­vel­op­ment is on the use of es­tab­lished Java libraries and standards.

“HotSpot”, from the OpenJDK project, is used as a Java Virtual Machine (JVM) to be the execution layer for Java code. In addition, the “GraalVM” de­vel­op­ment, which builds on HotSpot, can also be used. The latter allows Java code to be compiled into directly ex­e­cutable machine code. To un­der­stand the immediate benefit of using Quarkus, let’s first look at how Java ap­pli­ca­tions run with and without Quarkus.

How have Java ap­pli­ca­tions tra­di­tion­al­ly been executed?

The basic idea that made Java rev­o­lu­tion­ary when first in­tro­duced was as simple as it was cap­ti­vat­ing: Java would make it possible to write a program without being tied to a specific hardware or operating system. Such platform in­de­pen­dence is often summed up by the phrase “write once, run anywhere”. The as­so­ci­at­ed porta­bil­i­ty allows the program to be moved between platforms. What a great trick! So how does it work?

As with other pro­gram­ming languages, a Java program begins with source code that can be read by a human. In order to execute the in­struc­tions of the source text on a computer, cor­re­spond­ing in­struc­tions are generated in the format of the specific processor. With Java, there is another in­ter­me­di­ate step: The source text is first trans­lat­ed into an in­ter­me­di­ate format, the so-called bytecode, as is the case with the Python language. The bytecode is then executed in the “Java virtual machine” (JVM). In order to run a Java program on a device, a JVM must be installed on it.

The bytecode is tra­di­tion­al­ly in­ter­pret­ed for execution in the JVM. The bytecode in­struc­tions are trans­lat­ed piece by piece into machine code in­struc­tions and executed. The process of “just-in-time com­pi­la­tion” (JIT) is more effective. With that process, the bytecode is also converted into machine code, but further op­ti­miza­tions also come into play. In sum, running a Java program involves the following steps:

  1. Compiling Java source code to bytecode with the Java compiler command ‘javac’:
javac java_program.java
  1. Executing the Java bytecode with the Java runtime command ‘java’ - Machine code is then generated:
java java_program
Note

We are talking about a “virtual machine” here. Although the term is the same, in this instance, it does not refer to any kind of tech­nol­o­gy for vir­tu­al­iz­ing an operating system. Instead, in­ter­me­di­ate code is trans­lat­ed into machine code.

As practical as Java’s “write once, run anywhere” model is, the approach has some weak­ness­es. Using the JVM entails quite a sig­nif­i­cant overhead. On the one hand, a certain amount of time is required to start the JVM, which is added to the runtime of the actual app. On the other hand, in addition to higher memory con­sump­tion, there is a loss of per­for­mance. All of this plays a minor role in ap­pli­ca­tions that run for a long time. However, the approach is not very suitable for short-lived, container-based ap­pli­ca­tions. Ideally, these should start as soon as possible. A start time of several seconds is un­ac­cept­able.

How do Java ap­pli­ca­tions run with Quarkus?

In contrast to the native execution of Java ap­pli­ca­tions, Quarkus offers several ad­van­tages. Let’s dif­fer­en­ti­ate between the two modes supported by Quarkus:

  1. Op­ti­miza­tion of the bytecode and execution in the JVM
  2. Running as native code after com­pi­la­tion

Java code written with Quarkus can be executed normally in the JVM. However, there are con­sid­er­able ad­van­tages in terms of memory con­sump­tion and start time of a running ap­pli­ca­tion. To achieve this, Quarkus uses a few tricks. In par­tic­u­lar, a number of time-consuming steps are moved from the execution to the build process. This includes the steps that otherwise occur every time a Java ap­pli­ca­tion is executed:

  • Loading and parsing con­fig­u­ra­tions
  • Scanning the Java class path and resolving an­no­ta­tions
  • Creating entity models for databases or the like where ap­plic­a­ble

With Quarkus, these steps are carried out once and the results are cached for quick retrieval. Further per­for­mance op­ti­miza­tion comes in the form of Quarkus reducing the amount of dynamic in­for­ma­tion available at runtime. This is replaced by cor­re­spond­ing static con­structs. This is par­tic­u­lar­ly useful with regard to use in con­tain­ers. A con­tainer­ized ap­pli­ca­tion is usually not changed anyway and always runs in the same en­vi­ron­ment.

The second mode supported by Quarkus for running Java ap­pli­ca­tions is even more in­ter­est­ing. With “ahead-of-time com­pi­la­tion” (AOT), directly ex­e­cutable machine code is generated from the Java source text instead of bytecode, meaning there is no longer any need for a JVM on the target hardware. The program only runs on specific processor ar­chi­tec­ture and has to be re­com­piled for other platforms. However, this re­stric­tion is usually ir­rel­e­vant for use in con­tain­ers. The savings in memory con­sump­tion and ap­pli­ca­tion startup time achieved with AOT com­pi­la­tion are nothing short of breath­tak­ing. Compare the per­for­mance bench­marks shown here from the official Quarkus homepage:

Ap­pli­ca­tion Scenario Memory usage Time for first response
Quarkus + AOT REST 12 MB 0.02 s
Quarkus + AOT REST + CRUD 28 MB 0.04 s
Quarkus + JIT REST 73 MB 0.94 s
Quarkus + JIT REST + CRUD 145 MB 2.03 s
Cloud Native Stack REST 136 MB 4.3 s
Cloud Native Stack REST + CRUD 209 MB 9.5 s
Note

Regarding the ter­mi­nol­o­gy: REST means that only one web server is running in the container. In the REST + CRUD scenario, a database is running alongside the web server. For cloud native stack, the container contains a JVM, in addition to the Java ap­pli­ca­tion.

What is Quarkus used for?

Quarkus is not just another ap­pli­ca­tion framework. Instead, the software is meant to redefine what it means to develop ap­pli­ca­tions with Java. As a reminder: tra­di­tion­al­ly, it was more important for a Java ap­pli­ca­tion to run stably for a long time. How long the ap­pli­ca­tion took to start up was not critical.

Now, let’s consider container-based ap­pli­ca­tions. New con­tain­ers may be started au­to­mat­i­cal­ly by or­ches­tra­tion software. The ap­pli­ca­tion in the container should then be ready for immediate use. In addition, several redundant con­tain­ers are often launched for one service. The reduction in resource con­sump­tion achieved with Quarkus is mul­ti­plied ac­cord­ing­ly.

RedHat manager Alex Handy sums it up like this:

Quote

“When you think of server­less computing, mi­croser­vices and the [...] cloud, there’s one language you’re probably not [thinking of]: Java. And that’s a real shame. [...] Java was and is the workhorse language of business. It remains the third most popular language in the world […] It’s been the language of choice for cor­po­ra­tions that need to keep a single ap­pli­ca­tion up and running for years at a time.”

- Alex Handy, Source: https://the­new­stack.io/quarkus-gives-spring-boot-users-a-path-to-server­less-and-live-coding/

The ad­van­tages of Quarkus are obvious. However, the framework also has some lim­i­ta­tions. As such, Quarkus is not primarily intended to migrate existing Java ap­pli­ca­tions. Instead, it is worth using Quarkus as a starting point for new de­vel­op­ment. We will look at a few specific areas of ap­pli­ca­tion below. In all of the examples mentioned, Maven or Gradle is used as the build tool. The area of ap­pli­ca­tion is de­ter­mined by con­fig­ur­ing the ‘mvn’ or ‘gradle’ command. The build tool then au­to­mat­i­cal­ly generates the required con­fig­u­ra­tions and artifacts.

Executing mi­croser­vice ap­pli­ca­tions in Ku­ber­netes with Java and Quarkus

Ku­ber­netes is an or­ches­tra­tion software for container ap­pli­ca­tions. Using Ku­ber­netes with Docker con­tain­ers is quite common. In­di­vid­ual services of an ap­pli­ca­tion are saved as Docker images and managed by Ku­ber­netes. The or­ches­tra­tor takes over the man­age­ment of the con­tain­ers generated from the images: Ku­ber­netes starts, controls, and monitors the services. Often, multiple copies of a service are launched for load-sharing and increased fault tolerance. If one of the services crashes, the container is destroyed and a new container is created from the same image. Java Quarkus includes the con­fig­u­ra­tions that are necessary for use in Ku­ber­netes.

Im­ple­ment­ing REST APIs and server­less ap­pli­ca­tions with Java and Quarkus

REST is the long-es­tab­lished ar­chi­tec­ture style for web ap­pli­ca­tions. APIs in par­tic­u­lar are mostly im­ple­ment­ed following this approach. A REST-API is based on client-server ar­chi­tec­ture. Com­mu­ni­ca­tion takes place via the HTTP protocol using the “verbs” GET, POST, PUT, DELETE. These cor­re­spond to the well-known CRUD “verbs” (“create, read, update, delete”) from the database en­vi­ron­ment. Data exchange between an API and a user usually takes place via JSON.

Server­less computing is an al­ter­na­tive ar­chi­tec­ture for cloud-based ap­pli­ca­tions. In this model, also known as “Function as a Service” (FaaS), a single function runs briefly in a container. The function is called up, performs a cal­cu­la­tion, and is then switched off again. Despite the name, the server­less functions continue to run on servers. Pro­gram­mers no longer need to worry about them. With AWS Lambda, Google Cloud Functions, and Microsoft Azure Functions, server­less en­vi­ron­ments are available on all major cloud platforms. Java code can be used on these platforms with Quarkus.

Tip

Create your own REST-API on a dedicated server from IONOS.

Building reactive web apps with Java and Quarkus

In contrast to im­per­a­tive pro­gram­ming, reactive pro­gram­ming rep­re­sents a modern pro­gram­ming paradigm. The actions that should take place when certain events occur are described by a pro­gram­mer. The best-known rep­re­sen­ta­tives of this pro­gram­ming style are the frame­works “React” and “Vue”, written in JavaScript. Both of them focus on the creation of web-based user in­ter­faces. With Quarkus, ap­pli­ca­tions can be im­ple­ment­ed in an im­per­a­tive and reactive style. It is even possible to combine both paradigms.

Where is Quarkus used?

Quarkus was designed with the aim of op­ti­miz­ing Java ap­pli­ca­tions for use in con­tain­ers and cloud en­vi­ron­ments. The pos­si­bil­i­ty of compiling a Java program directly into machine code, however, opens up even more exciting ap­pli­ca­tion pos­si­bil­i­ties. Let’s have a look at the most in­ter­est­ing current areas of ap­pli­ca­tion for Quarkus.

First, let’s remember how a Java program developed with Quarkus runs. During the build process, the Java source code is compiled into bytecode, which is then trans­lat­ed into machine code when it is executed. Bytecode can be generated with Quarkus, which is then executed in a Java runtime en­vi­ron­ment, such as the HotSpot VM, via in­ter­pre­ta­tion or just-in-time (JIT) com­pi­la­tion. Depending on the con­fig­u­ra­tion, various per­for­mance-relevant op­ti­miza­tions come into play.

On the other hand, GraalVM, based on HotSpot, can be used to generate a native image using ahead-of-time (AOT) com­pi­la­tion. The native image is a binary file that contains all of the libraries and de­pen­den­cies necessary to run the ap­pli­ca­tion. Since no JVM is required for execution, the greatest per­for­mance gains are won from AOT com­pi­la­tion.

Java ap­pli­ca­tions in container en­vi­ron­ments

Ku­ber­netes is usually involved when using a Java app in con­tain­ers. A Java app packaged as a Docker image can also be used on an OpenShift cluster. You can test the use of Quarkus with Ku­ber­netes, for example, by using a minikube in­stal­la­tion on your local system.

Java functions in server­less en­vi­ron­ments

Use Quarkus to easily implement a function written in Java in server­less en­vi­ron­ments from Amazon, Google, and Microsoft.

Java programs in embedded systems

With the ability to create a native image from a Java ap­pli­ca­tion, Java code can also be used in embedded systems. AOT com­pi­la­tion is used here, which ensures low memory con­sump­tion and fast start-up times for a specific ap­pli­ca­tion.

Tip

Use Managed Ku­ber­netes from IONOS for your container apps.

Quarkus compared to other frame­works

Quarkus is suitable for a wide range of different ap­pli­ca­tion scenarios. Other frame­works are more specific to some extent. Let’s look at a couple of similar al­ter­na­tives:

  • React: This JavaScript framework has es­tab­lished itself as the standard for reactive pro­gram­ming.
  • Open Liberty: This IBM framework allows for the de­vel­op­ment of mi­croser­vice ap­pli­ca­tions with Java. Like Quarkus, Open Liberty comes with a live reload func­tion­al­i­ty.
  • Micronaut: With the Micronaut framework, mi­croser­vices and server­less ap­pli­ca­tions can be pro­grammed in Java. As with Quarkus, GraalVM is used here.
  • Spring/Spring Boot: Spring is probably the most popular Java framework for web ap­pli­ca­tions. Spring is based on GraalVM and, in addition to the creation of mi­croser­vices, it supports reactive pro­gram­ming and live reload. In a per­for­mance com­par­i­son, Quarkus beat Spring. An existing Spring project can be migrated to Quarkus rel­a­tive­ly easily.

What are the pros and cons of Quarkus?

The main advantage of de­vel­op­ing Java ap­pli­ca­tions with Quarkus is a gain in per­for­mance. This is par­tic­u­lar­ly important when using Java ap­pli­ca­tions in container en­vi­ron­ments. Per­for­mance benefits include:

  • Fast ap­pli­ca­tion start-up time
  • Low memory con­sump­tion
  • Almost immediate scaling of services
  • Lower space re­quire­ments for native images

In addition to the per­for­mance ad­van­tages, Quarkus shines because of its user-friend­li­ness. Ex­pe­ri­enced Java EE and Spring de­vel­op­ers can easily learn to use the framework. They also benefit from the fact that Quarkus is based on a solid framework. The following standard tech­nolo­gies are used, in addition to others:

  • Eclipse Mi­cro­Pro­file
  • Spring De­pen­den­cy Injection
  • Hibernate ORM

Quarkus also offers a live coding en­vi­ron­ment, in which de­vel­op­ers can quickly prototype. The live reload feature con­tributes to smooth de­vel­op­ment. After ac­ti­vat­ing the dev mode, changes to the source code and con­fig­u­ra­tion are compiled in the back­ground. The developer only has to reload the browser window to un­der­stand the changes.

Finally, we conclude with the dis­ad­van­tages of using Quarkus. These mostly result from the op­ti­miza­tions that come into play during com­pi­la­tion.

  • In par­tic­u­lar, reducing the dynamic in­for­ma­tion generated during runtime can lead to problems in some scenarios.
  • The severely limited pos­si­bil­i­ties for in­tro­spec­tion may make it difficult to debug an ap­pli­ca­tion.
  • The highly-optimized build process for native images takes a long time.

Quarkus is not intended for just any Java project. To some extent, using this framework requires processes to be converted.

Go to Main Menu