Class loading in Quarkus application

Digital engineer working on virtual blueprint building
Reading Time: 3 minutes

Depending on the mode that the application is running in, the Quarkus class loading architecture is slightly different. It is a flat class path when running a production application because everything is loaded into the system class loader.

For all environment other than production Quarkus uses the class loading architecture outlined here.

Bootstrapping Quarkus

Quarkus applications are created by the QuarkusBootstrap class in the independent-projects/bootstrap module. For the Quarkus application, this class is used to resolve each and every pertinent dependency, including runtime and deployment requirements. The final product of this process is a CuratedApplication, which includes all of the application’s class loading data.

The AugmentAction instance, which has the ability to generate production applications and start/restart runtime ones, may then be created using the CuratedApplication. It is not necessary to have any of the Quarkus deployment classes on the class path because the curation process will resolve them for you. This application instance exists within an isolated Class loader.

At the moment we have the following use cases for bootstrapping Quarkus:

  • Maven creating production application
  • Maven dev mode
  • Gradle creating a production application
  • Gradle dev mode
  • QuarkusTest (Maven, Gradle and IDE)
  • QuarkusUnitTest (Maven, Gradle and IDE)
  • QuarkusDevModeTest (Maven, Gradle and IDE)
  • Arquillian Adaptor

One of the goals of this refactor is to have all these different run modes boot Quarkus in fundamentally the same way.

ClassLoader implementations

  • Base classloader: This is usually the normal JVM System ClassLoader. In some environments, such as Maven, it may be different. This ClassLoader is used to load the bootstrap classes, and other ClassLoader instances will delegate the loading of JDK classes to it.
  • Augment classloader: It loads all -deployment artifacts and their dependencies required for the deployment. It does not load the application root or any hot deployed code. Even if the application restarts, this ClassLoader will continue to function (which is why it cannot load application classes that may be hot deployed). It is transformer safe, and its parent is the basic ClassLoader.
  • Deployment classLoader: It can load all application classes. Augment ClassLoader is the parent of this classLoader, so it can also load all deployment classes. This ClassLoader is isolated and non-persistent; it will be created again when the programme is launched. The context ClassLoader used to execute the build steps is this ClassLoader. It is also transformer safe.
  • Base Runtime classLoader: This loads all user dependencies as well as runtime extension dependencies (note that this may include duplicate copies of classes also loaded by the Augment ClassLoader). The application root or any recently deployed code is not loaded. Even if the program restarts, this ClassLoader will persist (which is why it cannot load application classes that may be hot deployed). The base ClassLoader serves as its parent.
  • Runtime classLoader: The classes for the application and other quickly deployable resources are loaded using this ClassLoader. When the application is restarted, it is recreated and has as its parent the base runtime ClassLoader. This means that it will have its own copies of almost every class from the resolved dependency list. 

Configuring Class Loading

It is possible to configure some aspects of class loading in dev and test mode. Note that class loading config is different to normal config, in that it does not use the standard Quarkus config mechanisms (as it is needed too early), so only supports application.propertiesFollow link to understand what all properties can be configured.

Hiding/Removing classes and resources from dependencies

Classes and resources that are dependent on other objects can be hidden or removed. This is an advanced option, but it can be useful at times. This is accomplished using the config parameter quarkus.class-loading.removed-resources .

quarkus.class-loading.removed-resources."io.quarkus\:quarkus-integration-test-shared-library"=io/quarkus/it/shared/RemovedResource.class

This will remove the RemovedResource.class file from the io.quarkus:quarkus-integration-test-shared-library artifact. Even though this option is a class loading option it will also affect the generated application, so when the application is created removed resources will not be accessible.

References

https://quarkus.io/guides/class-loading-reference