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­tern­at­ive models: container-based ap­plic­a­tions, mi­croservices, server­less computing, and reactive web apps have es­tab­lished them­selves in the main­stream. These types of ap­plic­a­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­plic­a­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 re­volu­tion­ising the creation of Java ap­plic­a­tions.

What makes Quarkus special?

Quarkus is a framework developed by RedHat for creating Java ap­plic­a­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 Kuber­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­ecut­able machine code. To un­der­stand the immediate benefit of using Quarkus, let’s first look at how Java ap­plic­a­tions run with and without Quarkus.

How have Java ap­plic­a­tions tra­di­tion­ally been executed?

The basic idea that made Java re­volu­tion­ary when first in­tro­duced was as simple as it was cap­tiv­at­ing: Java would make it possible to write a program without being tied to a specific hardware or operating system. Such platform in­de­pend­ence is often summed up by the phrase ‘write once, run anywhere’. The as­so­ci­ated port­ab­il­ity 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­res­pond­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­lated 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­ally in­ter­preted for execution in the JVM. The bytecode in­struc­tions are trans­lated piece by piece into machine code in­struc­tions and executed. The process of ‘just-in-time com­pil­a­tion’ (JIT) is more effective. With that process, the bytecode is also converted into machine code, but further op­tim­isa­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­no­logy for vir­tu­al­ising an operating system. Instead, in­ter­me­di­ate code is trans­lated into machine code.

As practical as Java’s ‘write once, run anywhere’ model is, the approach has some weak­nesses. Using the JVM entails quite a sig­ni­fic­ant 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­form­ance. All of this plays a minor role in ap­plic­a­tions that run for a long time. However, the approach is not very suitable for short-lived, container-based ap­plic­a­tions. Ideally, these should start as soon as possible. A start time of several seconds is un­ac­cept­able.

How do Java ap­plic­a­tions run with Quarkus?

In contrast to the native execution of Java ap­plic­a­tions, Quarkus offers several ad­vant­ages. Let’s dif­fer­en­ti­ate between the two modes supported by Quarkus:

  1. Op­tim­isa­tion of the bytecode and execution in the JVM
  2. Running as native code after com­pil­a­tion

Java code written with Quarkus can be executed normally in the JVM. However, there are con­sid­er­able ad­vant­ages in terms of memory con­sump­tion and start time of a running ap­plic­a­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­plic­a­tion is executed:

  • Loading and parsing con­fig­ur­a­tions
  • Scanning the Java class path and resolving an­nota­tions
  • Creating entity models for databases or the like where ap­plic­able

With Quarkus, these steps are carried out once and the results are cached for quick retrieval. Further per­form­ance op­tim­isa­tion comes in the form of Quarkus reducing the amount of dynamic in­form­a­tion available at runtime. This is replaced by cor­res­pond­ing static con­structs. This is par­tic­u­larly useful with regard to use in con­tain­ers. A con­tain­er­ised ap­plic­a­tion is usually not changed anyway and always runs in the same en­vir­on­ment.

The second mode supported by Quarkus for running Java ap­plic­a­tions is even more in­ter­est­ing. With ‘ahead-of-time com­pil­a­tion’ (AOT), directly ex­ecut­able 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­ev­ant for use in con­tain­ers. The savings in memory con­sump­tion and ap­plic­a­tion startup time achieved with AOT com­pil­a­tion are nothing short of breath­tak­ing. Compare the per­form­ance bench­marks shown here from the official Quarkus homepage:

Ap­plic­a­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­min­o­logy: 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­plic­a­tion.

What is Quarkus used for?

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

Now, let’s consider container-based ap­plic­a­tions. New con­tain­ers may be started auto­mat­ic­ally by or­ches­tra­tion software. The ap­plic­a­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­ingly.

RedHat manager Alex Handy sums it up like this:

Quote

‘When you think of server­less computing, mi­croservices 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­por­a­tions that need to keep a single ap­plic­a­tion up and running for years at a time.’

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

The ad­vant­ages of Quarkus are obvious. However, the framework also has some lim­it­a­tions. As such, Quarkus is not primarily intended to migrate existing Java ap­plic­a­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­plic­a­tion below. In all of the examples mentioned, Maven or Gradle is used as the build tool. The area of ap­plic­a­tion is de­term­ined by con­fig­ur­ing the ‘mvn’ or ‘gradle’ command. The build tool then auto­mat­ic­ally generates the required con­fig­ur­a­tions and artifacts.

Executing mi­croservice ap­plic­a­tions in Kuber­netes with Java and Quarkus

Kuber­netes is an or­ches­tra­tion software for container ap­plic­a­tions. Using Kuber­netes with Docker con­tain­ers is quite common. In­di­vidu­al services of an ap­plic­a­tion are saved as Docker images and managed by Kuber­netes. The or­ches­trat­or takes over the man­age­ment of the con­tain­ers generated from the images: Kuber­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­ur­a­tions that are necessary for use in Kuber­netes.

Im­ple­ment­ing REST APIs and server­less ap­plic­a­tions with Java and Quarkus

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

Server­less computing is an al­tern­at­ive ar­chi­tec­ture for cloud-based ap­plic­a­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­vir­on­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­at­ive pro­gram­ming, reactive pro­gram­ming rep­res­ents 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­res­ent­at­ives of this pro­gram­ming style are the frame­works ‘React’ and ‘Vue’, written in JavaS­cript. Both of them focus on the creation of web-based user in­ter­faces. With Quarkus, ap­plic­a­tions can be im­ple­men­ted in an im­per­at­ive and reactive style. It is even possible to combine both paradigms.

Where is Quarkus used?

Quarkus was designed with the aim of op­tim­ising Java ap­plic­a­tions for use in con­tain­ers and cloud en­vir­on­ments. The pos­sib­il­ity of compiling a Java program directly into machine code, however, opens up even more exciting ap­plic­a­tion pos­sib­il­it­ies. Let’s have a look at the most in­ter­est­ing current areas of ap­plic­a­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­lated into machine code when it is executed. Bytecode can be generated with Quarkus, which is then executed in a Java runtime en­vir­on­ment, such as the HotSpot VM, via in­ter­pret­a­tion or just-in-time (JIT) com­pil­a­tion. Depending on the con­fig­ur­a­tion, various per­form­ance-relevant op­tim­isa­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­pil­a­tion. The native image is a binary file that contains all of the libraries and de­pend­en­cies necessary to run the ap­plic­a­tion. Since no JVM is required for execution, the greatest per­form­ance gains are won from AOT com­pil­a­tion.

Java ap­plic­a­tions in container en­vir­on­ments

Kuber­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 Kuber­netes, for example, by using a minikube in­stall­a­tion on your local system.

Java functions in server­less en­vir­on­ments

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

Java programs in embedded systems

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

Tip

Use Managed Kuber­netes from IONOS for your container apps.

Quarkus compared to other frame­works

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

  • React: This JavaS­cript 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­croservice ap­plic­a­tions with Java. Like Quarkus, Open Liberty comes with a live reload func­tion­al­ity.
  • Micronaut: With the Micronaut framework, mi­croservices and server­less ap­plic­a­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­plic­a­tions. Spring is based on GraalVM and, in addition to the creation of mi­croservices, it supports reactive pro­gram­ming and live reload. In a per­form­ance com­par­is­on, Quarkus beat Spring. An existing Spring project can be migrated to Quarkus re­l­at­ively easily.

What are the pros and cons of Quarkus?

The main advantage of de­vel­op­ing Java ap­plic­a­tions with Quarkus is a gain in per­form­ance. This is par­tic­u­larly important when using Java ap­plic­a­tions in container en­vir­on­ments. Per­form­ance benefits include:

  • Fast ap­plic­a­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­form­ance ad­vant­ages, Quarkus shines because of its user-friend­li­ness. Ex­per­i­enced Java EE and Spring de­velopers 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­no­lo­gies are used, in addition to others:

  • Eclipse Mi­cro­Pro­file
  • Spring De­pend­ency Injection
  • Hibernate ORM

Quarkus also offers a live coding en­vir­on­ment, in which de­velopers can quickly prototype. The live reload feature con­trib­utes to smooth de­vel­op­ment. After ac­tiv­at­ing the dev mode, changes to the source code and con­fig­ur­a­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­vant­ages of using Quarkus. These mostly result from the op­tim­isa­tions that come into play during com­pil­a­tion.

  • In par­tic­u­lar, reducing the dynamic in­form­a­tion generated during runtime can lead to problems in some scenarios.
  • The severely limited pos­sib­il­it­ies for in­tro­spec­tion may make it difficult to debug an ap­plic­a­tion.
  • The highly-optimised 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