Getting Started with Quarkus Basics

0% found this document useful (0 votes)
116 views10 pages
This document discusses getting started with Quarkus, a Kubernetes-native Java framework. It provides an example of validating a Java class with constraints in Quarkus, which uses interfaces…

Uploaded by

Laszlo Kamler
  • Getting Started with Quarkus

Chapter 2 – Getting Started with Quarkus

@Validated

@NotNull
private String message;

@NotNull

private String name;

@Valid

public String getMessage() { return [Link]; }


public void setMessage(String message) { [Link] = message; }

public String getName() { return [Link]; }


public void setName(String name) { [Link] = name; }

@NotNull
@Positive
private Integer prizeAmount;

@NotEmpty
private List<String> recipients;
public Integer getPrizeAmount() { return [Link]; }
public void setPrizeAmount(Integer prizeAmount) { [Link] =
prizeAmount; }
public List<String> getRecipients() { return [Link]; }
public void setRecipients(List<String> recipients) { [Link] =
recipients; }
}
}

Listing 2.5 shows that required fields must be annotated. Additionally, Spring’s
@Validated annotation must be placed on the class to enable any validation, and
the @Valid annotation must exist on any nested class attributes. Additional bean vali-
dation annotations can be used for more advanced validation, such as the @Positive
annotation placed on the prizeAmount nested class.

Quarkus
There are a few differences in Quarkus. First, Quarkus uses interfaces rather than

approach when it comes to required versus optional properties. By default, all prop-

an Optional
the @Valid or @Validated annotations to perform validation. Quarkus validates a
-
dation extension is present.

Quarkus for Spring Developers | 31


Chapter 2 – Getting Started with Quarkus

Quarkus by Listing 2.6.

@WithName(“message”) Note: For consistency with


String getMessage(); the Spring Boot example
in Listing 2.5, the Quarkus
example in Listing 2.6 uses
@WithDefault(“!”) method names derived from

The @WithName annotations


@WithName(“name”) are unnecessary if the
Optional<String> getName(); method names are the same
as the property name. For
@WithName(“content”) example, if getMessage()
was renamed to message(),
the preceding @WithName
annotation could be removed.
@Positive
@WithName(“prizeAmount”)
Integer getPrizeAmount();

@WithName(“recipients”)
List<String> getRecipients();
}
}

The previous section showed how to inject values into properties during configura-
tion. In practice, it is often necessary to inject different sets of configuration values
at different times. For example, the configurations for testing are often different
from the configurations for running the application in production. Both Quarkus
and Spring support this capability by the concept of a Profile. However, one ma-
jor difference is that Quarkus unifies all configurations for all profiles into a single
configuration file.

Description
dev Activated when running in development mode (i.e., mvn quarkus:dev).
test Activated when running tests (i.e., mvn verify).
prod

Quarkus for Spring Developers | 32


Chapter 2 – Getting Started with Quarkus

Mechanism Example Similar Spring action


./mvnw package
system property (declared within
[Link]) or

QUARKUS_PROFILE export QUARKUS_PROFILE= export


environment variable

If both the system property and the environment variable are set, the system property

.env

_{PROFILE-NAME}_KEY=value

.env

_DEV_GREETING_NAME=Quarkus for Spring Developer

Example
Return to the src/main/resources/[Link]
present is the one added previously. The value of the [Link] property will be
Quarkus (properties)

%[Link]=Quarkus for Spring Developer (dev)


%[Link]=Quarkus for Spring Developer (prod)
%[Link]=RESTEasy

Your [Link]

[Link]=Quarkus (properties)
%[Link]=Quarkus for Spring Developer (dev)
%[Link]=Quarkus for Spring Developer (prod)
%[Link]=RESTEasy

Return to the browser window and refresh the page. You should now see the text Hello
Quarkus for Spring Developer (dev). Return to the terminal where the ./mvnw
quarkus:dev command is running and terminate dev mode, typically using
keystrokes.

Now run the application outside of dev mode to activate the prod

$ ./mvnw clean package

Quarkus for Spring Developers | 33


Chapter 2 – Getting Started with Quarkus

[Link] will be created inside the target/


quarkus-app directory. Now run the application by running the following command:

$ java -jar target/quarkus-app/[Link]

When the application starts up, it should print out . Also, no-
tice the startup time. In most cases, the startup time will be less than one second. This

applications to start up without the delays found in many Java applications.

Return to the browser window and refresh the page. You should now see the text Hello
Quarkus for Spring Developer (prod). Return to the terminal and terminate the
running application in the same way as before.

Dependency Injection

needs to function correctly. Dependency injection was one of the key components of
Spring Framework. It became so popular that Java and the Java EE platform followed
what Spring was doing. Today, Contexts and Dependency Injection (CDI) for Java 2.0
(JSR-365) [2.23] is the base for ArC [2.24], the dependency injection framework used
by Quarkus.

One of the main differences between dependency injection in Quarkus and Spring
is that Quarkus performs as much of the injection as possible at build time, whereas
Spring performs injection at runtime. Quarkus’s build-time augmentation leads to much
better startup performance because ArC just needs to load all the metadata that was
already computed at build time.

attributes. Additionally, in both Spring and Quarkus, the default process of matching
a bean to an injection point is done via type. This pattern is synonymous with Spring’s
“injection by type.” In Quarkus, exactly one bean must be assignable to an injection
point; otherwise, the build fails. In Spring, if there were multiple beans of the same type,
the application would build but fail to start.

whether the application is correct as part of their local development or CI/CD pipelines.
There is no need to wait until the application is deployed into an environment and start-

developer productivity and lower project costs.

Scopes
Quarkus and Spring also support the notion of bean scopes. Table 2.8 describes the
scopes available for a Quarkus application, along with the Spring equivalents. Quarkus
extensions can provide other custom scopes. For example, the quarkus-narayana-jta
extension provides @[Link].

Quarkus for Spring Developers | 34


Chapter 2 – Getting Started with Quarkus

Table 2.8: Available Quarkus bean scopes.

Quarkus scope Spring equivalent Quarkus description


annotation
@ApplicationScoped @Scope(“singleton”) A single bean instance is used for the
application and shared among all injection
points. The instance is created lazily once a
method is invoked on its proxy.
@Singleton @Scope(“singleton”) Just like @ApplicationScoped except that
no proxy is used. The instance is created when
an injection point resolves to an injected @
Singleton bean.
@RequestScoped @Scope(“request”) The bean instance is associated with the
current request, usually an HTTP request.
@Dependent @Scope(“prototype”) A pseudo-scope. The instances are not shared,
and every injection point spawns a new instance
of the dependent bean. The lifecycle of a
dependent bean is bound to the bean injecting
it. The bean will be created and destroyed along
with the bean injecting it.
@SessionScoped @Scope(“session”) This scope is backed by a [Link].
[Link] object. This annotation
is available only if the quarkus-undertow
extension is used.

@ApplicationScoped or @Singleton?
Quarkus provides two different scopes representing Spring’s singleton scope:
@ApplicationScoped and @Singleton. Which one to use depends on what you are
trying to accomplish.

An @Singleton bean has no proxy. Proxies should be familiar to Spring users because
they are the backbone behind Spring’s dependency injection mechanism. When the
Spring runtime injects a bean into another bean, the injection is usually a proxy to the
actual bean. It’s a placeholder where Spring can wrap the bean with some alternate
implementation or delay the bean’s instantiation.

Because an @Singleton bean lacks a proxy, the bean is created eagerly when an instance
@Singleton bean
can not be mocked. By contrast, an instance of an @ApplicationScoped bean is created
lazily once an instance is acted upon @ApplicationScoped

can with an @Singleton bean.

As a general rule of thumb, the recommendation is to use @ApplicationScoped by


default unless there is a compelling reason to use @Singleton. @ApplicationScoped

Example
Let’s take the example being used so far in this chapter and change it to use de-
pendency injection. All the logic for computing a greeting message resides in the
GreetingResource class. Follow these steps to create a new class containing the
required functionality and refactor GreetingResource to inject a new bean.

1. Return to the terminal and execute ./mvnw quarkus:dev there.


2. In the src/main/java/org/acme directory, create a new Java class with the
[Link].

Quarkus for Spring Developers | 35


Chapter 2 – Getting Started with Quarkus

3. Add the @ApplicationScoped annotation to the class.


4. Inject the greeting attribute into the GreetingService class exactly as in the
GreetingResource class, by adding a attribute and a constructor
injecting the .
5. Inside GreetingService, create a getGreeting method:
public String getGreeting() {
return “Hello “ + [Link];
}

6. Open the GreetingResource class.


7. Remove the greeting attribute from the class.
8. Add a new attribute to the class:
9. Change the constructor within the class to instead inject a GreetingService argument:
public GreetingResource(GreetingService greetingService) {
[Link] = greetingService;
}

10. Change the return of the hello() method to be:


return [Link]();

Listings 2.8 and 2.9 show the completed classes.

Listing 2.8: Completed [Link].


@ApplicationScoped
public class GreetingService {

greeting) {
[Link] = greeting;
}

public String getGreeting() {


return “Hello “ + [Link];
}
}

Listing 2.9: Completed [Link].


@Path(“/hello-resteasy”)
public class GreetingResource {

public GreetingResource(GreetingService greetingService) {


[Link] = greetingService;
}

@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return [Link]();
}
}

Quarkus for Spring Developers | 36


Chapter 2 – Getting Started with Quarkus

Return to your browser and refresh the page. You should see the text Hello Quarkus
for Spring Developer (dev). Return to the terminal where the ./mvnw quarkus:dev
command is running and terminate Dev Mode.

The GreetingResource class uses constructor injection to inject the GreetingService.

-
ples in this book promote constructor injection. Listing 2.10 shows what the Greeting
Resource
Quarkus advises against
using private

@Path(“/hello-resteasy”)
public class GreetingResource {
@Inject up build and application
GreetingService greetingService; startup times and reduces
an application’s memory
@GET footprint.
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return [Link]();
}
}

Lifecycle Callbacks
Both Quarkus and Spring support creating lifecycle callbacks on beans, supporting the
and @PreDestroy annotations found in the [Link]
package. Methods annotated with are invoked before the bean
instance is placed into service. It is safe to perform bean initialization within the method.
Methods annotated with @PreDestroy are invoked before the destruction of the bean
instance. It is safe to perform cleanup tasks within the method.

Native Image
Quarkus’s design accounted for native compilation from the onset. A Quarkus native
executable starts much faster and uses far less memory than a traditional JVM. Sim-
ilar native image capabilities in Spring are still considered experimental or beta as of
this writing.

To build a native image and run native image tests, you need to install either a distribu-
tion of GraalVM or a working container runtime. Additionally, Maven or Gradle has some Note: Maven and Gradle
scaffolding to facilitate the building of the native image and launching it for tests. scaffolding isn’t discussed in
this book. However, it is doc-
The following example assumes that GraalVM CE or Mandrel has been downloaded, umented extensively in the
and either the GRAALVM_HOME environment variable has been set to its location. Once Quarkus guide for building
all the requirements are met, a native image can be built using a simple command on a native executable [2.25],
the terminal: along with how to use a
container runtime environ-
$ ./mvnw package -Pnative ment instead of installing a
GraalVM distribution locally.
Native compilation can take several minutes to complete. Once complete, the native The [Link] gen-
executable chapter-2-simple-project-1.0.0-SNAPSHOT-runner can be found in erator provides everything
the project’s target directory. On the terminal, execute the following: needed for Maven or Gradle
to function properly.
$ ./target/chapter-2-simple-project-1.0.0-SNAPSHOT-runner

Quarkus for Spring Developers | 37


Chapter 2 – Getting Started with Quarkus

The command will produce the following output:

__ ____ __ _____ ___ __ ____ ______


--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
INFO [[Link]] (main) chapter-2-simple-project 1.0.0-SNAPSHOT native (powered
by Quarkus [Link]) started in 0.015s. Listening on: [Link]

INFO [[Link]] (main) Installed features: [cdi, resteasy,


smallrye-context-propagation]

From this output, notice the application started in just 15 milliseconds. Return to
your browser and refresh the page. You should see the text Hello Quarkus for
Spring Developer (prod).

Resident Set Size


Resident set size (RSS) [2.26] is the amount of memory occupied by a process. Calcu-
lating the RSS of a process is dependent on the operating system used. For macOS and
Linux-based systems, the commands also vary by shell. In the bash shell on macOS or
Red Hat Enterprise Linux, running the following command:

$ ps -o pid,rss,command -p $(pgrep -f chapter-2-simple-project-1.0.0-SNAPSHOT-runner)

results in the following output:

13949 18604 ./target/chapter-2-simple-project-1.0.0-SNAPSHOT-runner

The 18604 value in the RSS column is the RSS size, in kilobytes, of the running process. Note: The startup time and
Dividing that number by 1024 gives an RSS size of just over 18 megabytes for the run- RSS output was gathered
ning application’s memory footprint. from a terminal running on
macOS. Your startup time
Return to the terminal where the ./target/chapter-2-simple-project-1.0.0- and RSS output may vary.
SNAPSHOT-runner command is running and terminate it the same way as before.

Testing
Testing is essential in any application to ascertain that the required functionality is
implemented correctly. Both Quarkus and Spring include testing frameworks based on
JUnit 5 [2.27] and Mockito [2.28].

Continuous Testing
As mentioned in Chapter 1, Quarkus enables test-driven development by under-
standing which tests are affected by classes and methods within the application. As
changes are made to the application source code, Quarkus can automatically rerun
affected tests in the background, giving developers instant feedback about the code
they are writing.

To enable continuous testing, return to the terminal and execute ./mvnw quarkus:dev.
Once the Quarkus banner appears, notice in the terminal the following text at the very
bottom: Tests paused, press [r] to resume, also shown in Figure 2.6.

Quarkus for Spring Developers | 38


Chapter 2 – Getting Started with Quarkus

Figure 2.6: Continuous testing output.

Press r in the terminal to enable continuous testing. The console should show output
similar to:

--
All 1 tests are passing (0 skipped), 1 tests were run in 4552ms.

Unit Testing
Unit testing aims to isolate a single class so methods on the class can be tested. The
test retains complete control over any external dependencies the class under test may
have. One way to facilitate control over dependencies is to use constructor injection
when creating classes, as seen in the previous examples. Bootstrapping the entire
application isn’t necessary in most cases when using this pattern with either Spring or
Quarkus. Simply constructing a class and passing mocks or other required classes via
the constructor and then asserting results is good enough.

Let’s see this in action by adding a test class for the GreetingService class created
earlier. Create a new Java class called GreetingServiceTest inside the src/test/
java/org/acme folder. Inside that class, add a single test method and save the changes:

@Test
public void getGreetingOk() {
[Link](“Hello Quarkus”,
new GreetingService(“Quarkus”).getGreeting());
}

Listing 2.11 shows the entire GreetingServiceTest class.

Listing 2.11: [Link].


public class GreetingServiceTest {
@Test
public void getGreetingOk() {
[Link](“Hello Quarkus”, new GreetingSer-
vice(“Quarkus”).getGreeting());
}
}

Return to the terminal and notice that Quarkus automatically ran the test successfully.
Also notice that only one test was run: the test that was just created. The existing test in
the [Link] class was not rerun.

--
All 2 tests are passing (0 skipped), 1 tests were run in 53ms.

There are times when you need the underlying framework to provide capabilities
for you to write tests. One such example is when exposing RESTful endpoints. In
that case, a test would issue an HTTP request with specific parameters, such as a
request path, headers, and request parameters, and then perform assertions on
some returned JSON structure. This kind of testing can’t be done by instantiating a
class and calling methods directly on it, either in Quarkus or in Spring.

Quarkus for Spring Developers | 39


Chapter 2 – Getting Started with Quarkus

When the chapter-2-simple-project project was generated earlier, a test class


named GreetingResourceTest inside the src/test/java/org/acme folder was
generated along with the project. The specifics of the REST-assured frame-
work [2.29] used in this example will be discussed in detail in Chapter 3. However,
the testHelloEndpoint method asserts that, when issuing an HTTP GET to
the /hello-resteasy endpoint, the result is the value Hello RESTEasy. Listing 2.12
shows the test in its current form.

Listing 2.12: [Link].


@QuarkusTest
public class GreetingResourceTest {
@Test
public void testHelloEndpoint() {
given()
.when().get(“/hello-resteasy”)
.then()

.body(is(“Hello RESTEasy”));
}
}

Another thing to notice is the @QuarkusTest annotation at the top of the class. This
annotation is similar to the @SpringBootTest annotation on tests in a Spring Boot
application. The main difference in Quarkus is that the application is started only once
and reused for all tests annotated with @QuarkusTest. In contrast, in Spring Boot,
the application is started before each test class annotated with @SpringBootTest
and then shut down after all tests in the class are executed. Subsequently, a Spring
application restarts when the next test class annotated with @SpringBootTest is
executed.

Additionally, classes annotated with @QuarkusTest can inject other beans, as we’ll
see in the next section. Quarkus ensures that the state of the beans in the running
application matches tests or test class’s requirements without having to restart the
application.

Mocking
Earlier the GreetingResource class was refactored to inject a GreetingService, so
the GreetingResourceTest class test should be refactored as well. The Greetin-
gResource class needs to be tested in isolation, so it would be better for the test to
mock the GreetingService class.

The quarkus-junit5-mockito library is required to accomplish this. The quarkus-


junit5-mockito library contains many utilities, classes, and annotations that make
Mockito easier to use within Quarkus. Many of these are similar to the spring-boot-test
library provided by Spring Boot.

Open the project’s [Link] <dependencies> section. Towards the


end of the the section, add the following:

<dependency>
<groupId>[Link]</groupId>
<artifactId>quarkus-junit5-mockito</artifactId>
<scope>test</scope>
</dependency>

Quarkus for Spring Developers | 40

Common questions

Powered by AI

In Quarkus, the @QuarkusTest annotation is used to run tests with the application starting only once, and it is reused across all tests annotated with @QuarkusTest. This efficient resource management contrasts with Spring's @SpringBootTest, where the application starts and shuts down for each test class, potentially leading to higher resource consumption. Moreover, in Quarkus, the application state is preserved across tests, ensuring consistent test results without application restarts .

In Quarkus, dependency injection is mainly done at build time, which improves startup performance because necessary metadata has already been computed and only needs to be loaded. This differs from Spring, where dependency injection is executed at runtime, potentially leading to longer startup times. Quarkus requires exactly one bean to be assignable to an injection point, causing a build failure if this condition is not met. In contrast, Spring allows applications to build even if multiple beans are assignable, with failure occurring at startup instead. Both frameworks largely match a bean to an injection point via type, following a pattern known as "injection by type" .

The quarkus-junit5-mockito library simplifies the use of Mockito within Quarkus, making it easier to mock dependencies during testing. It provides utilities, classes, and annotations that streamline the integration of mock objects, aiding in the isolation of components under test. Similar to Spring's spring-boot-test library, it facilitates the simulation of complex interactions without relying on fully initialized application contexts. This capability enhances the precision and efficiency of test creation and execution .

Quarkus's approach to maintaining a low resident set size (RSS) results in a small memory footprint for running processes, contributing to its performance advantages. By executing processes with minimal memory requirements, Quarkus ensures efficient resource usage, allowing the application to run effectively even on constrained environments. This approach supports the lower startup times and enhanced runtime efficiency that characterize Quarkus compared to traditional Java platforms .

Constructor injection provides better control over dependencies when writing tests in Quarkus because it allows direct assignment of mocked dependencies to the classes under test. This method prevents unintended state changes due to shared dependencies and makes tests more predictable and easier to maintain. It forgoes the need to bootstrap the entire application, leading to faster and more isolated unit tests. This advantage is significant over field injection, where dependencies are inherently shared and may introduce variability across tests .

Quarkus optimizes application startup time by extensively processing dependency injection and other preparations during build time, rather than at runtime. This build-time augmentation allows Quarkus to load metadata efficiently at startup, resulting in significantly faster initialization times, often less than one second even for complex applications. This contrasts with traditional Java applications, which may experience delays due to runtime handling of dependency management and other tasks .

Continuous testing in Quarkus allows for automated rerun of tests that are affected by code changes, providing immediate feedback to developers. This feature ensures test accuracy as classes and methods are modified during development. Continuous testing supports rapid detection of issues and validation of functionality changes, reducing the development cycle time and increasing productivity by allowing developers to focus on code improvement without manually managing test execution .

In Quarkus, @ApplicationScoped is analogous to Spring's @Scope('singleton'), in that it uses a single bean instance shared across injection points. However, it uses a lazy creation mechanism by invoking a method on its proxy. @Singleton in Quarkus is also similar to @Scope('singleton') in Spring, but without the use of proxies, and instances are created eagerly when resolved at an injection point. The choice between @ApplicationScoped and @Singleton in Quarkus depends on the need for lazy initialization and proxy utilization, where @ApplicationScoped is recommended unless specific eager initialization or proxy-free requirements are needed .

Quarkus promotes test-driven development by detecting which tests are affected by code changes and automatically rerunning them, providing immediate feedback. This feature allows developers to validate the functionality they are working on instantly, reducing the need to wait until the application is fully built and deployed to identify issues. This capability significantly enhances developer productivity and reduces project costs by ensuring that developers can correct errors early in the development lifecycle .

Quarkus unifies all configurations for all profiles into a single configuration file, which differs from Spring's approach where separate configuration files can be used for each profile. This means that in Quarkus, different sets of configuration values can be managed using a single file with specific profile keys, such as %[profile-name].property=value .

Chapter 2 – Getting Started with Quarkus
Quarkus for Spring Developers | 31
@Validated
  @NotNull
  private String message;
Chapter 2 – Getting Started with Quarkus
Quarkus for Spring Developers | 32
Quarkus by Listing 2.6.
  @WithName(“message”)
Chapter 2 – Getting Started with Quarkus
Quarkus for Spring Developers | 33
Mechanism
Example
Similar Spring action
 
system
Chapter 2 – Getting Started with Quarkus
Quarkus for Spring Developers | 34
quarkus-run.jar will be created inside the target
Chapter 2 – Getting Started with Quarkus
Quarkus for Spring Developers | 35
Quarkus scope 
annotation
Spring equivalent
Quark
Chapter 2 – Getting Started with Quarkus
Quarkus for Spring Developers | 36
3. Add the @ApplicationScoped annotation to the c
Chapter 2 – Getting Started with Quarkus
Quarkus for Spring Developers | 37
Return to your browser and refresh the page. You
Chapter 2 – Getting Started with Quarkus
Quarkus for Spring Developers | 38
The command will produce the following output:
__
Chapter 2 – Getting Started with Quarkus
Quarkus for Spring Developers | 39
Figure 2.6: Continuous testing output.
Press r in
Chapter 2 – Getting Started with Quarkus
Quarkus for Spring Developers | 40
When the chapter-2-simple-project project was gen

You might also like