📜 ⬆️ ⬇️

Class loading in application servers, features of JBoss AS 7

Java is characterized by dynamic class loading. For searching and loading, the mechanism of delegating classloaders is used. In the Java SE environment, their number is limited to 2-3, but in application servers it approaches 10 hierarchical classloaders. This explains the large startup time (usually from a minute) and the deployment of applications.

In JBoss AS 7, developers managed to drastically reduce startup time (an empty appserver runs in 3-4 seconds on a workstation). This was facilitated by the new class loading system in this application server. This approach still has its drawbacks.

This article deals with the mechanism of loading classes in various environments, the features of working with JBoss AS 7, interfacing with the Apache Maven build system and IDE IntelliJ IDEA.

Class loading in java


According to Java Language Specifiaction, JVM dynamically loads, binds, and initializes classes. Class search and loading is carried out by the classplayer hierarchy.
')
At the start of the Java machine, the bootstrap classloader is used (which is responsible for loading the base classes from rt.jar and other parts of the JVM implementation). In the future, there is usually a delegation of the system classloader , which searches within the specified CLASSPATH program. And in the simplest case, this is limited.

In the future, the class file is loaded and parsed and linked (verification, preparation and resolution of class dependencies). After that, initialization occurs. That is, the loading of the class description, the initialization of static fields and the execution of static initializers occur
"Lazy", if necessary. The lazy initialization pattern with a static-holder, described in Effective Java, is based on this .

In environments such as servlet containers, application servers, and OSGi, things get more complicated. They have a complex hierarchy of class-breakers, designed to give access to what is allowed (for example, libraries provided by the environment) and, at the same time, to isolate different “modules” from each other.
That is, in two loaded web applications there may be different versions of the same class that will be visible only to the corresponding applications.

Naturally, the class may not be detected - then an error occurs loading it, as a rule, leading to a drop in the JVM, if it is not intercepted (as is done by the application server).

Normal loading structure in servlet container (tomcat, jetty)


In this type of environment, the classloader hierarchy is, of course, complicated. After the system classloader , which is designed to launch the servlet-container itself, the search is delegated further along the chain.

For each application deployed in a container, a classifier is created that searches by classes in WEB-INF / classes and jar-files in WEB-INF / lib (all within the limits of this application's war).

Next comes the common classloader delegation, which searches for libraries common to all clients (in CATALINA_HOME / lib in the case of tomcat).

Application servers


A further story will concern the loading of classes by the glassfish app server. As expected, the first in a long boot chain bootstrap classloader . After it, control is transferred to the public-api classloader , which is responsible for the classes, interfaces, and annotations of the Java EE stack and other APIs exported by the application server. The next is a common classloader familiar to us by tomcat, which is responsible for the libraries common to the entire app-server. Next in the chain is the connector classloader , which allows all applications to access the JCA. After that, control is transferred to the lifecyclemodule classloader . It is designed to load classes that manage the life cycle of beans in applications. The next character is the applib classloader , much like common, but works with some groups of applications. And last of all, the archive classloader works, working with classes from WAR / EAR / RAR / EJB-JAR, etc.

Such a complex system of searching and loading classes makes it possible to simplify the classes themselves, more clearly divide them into levels of abstraction, and avoid duplication of libraries. The main disadvantage is the enormous awkwardness of this system and, as a result, a large load time for the app-server and application deployment.

Features of the hero of the narrative JBoss AS 7


JBoss AS 6 is very much like glassfish in its structure. By start time - the same. What is fundamentally healed version 7? Why she attracted the attention of developers?

The answer is simple: a very quick start. Previously, there was no application server starting in seconds. AS 6 and GlassFish start a minute at best. For a developer who has unstretched glassfish dies at PermGen with constant redeployed, this is just a salvation.

So, we go to the technical side of the issue. How did you manage to reach such speeds? The basis for solving the problem of the slow work of hierarchical classes is JBoss Modules . This project aims at a modular (rather than hierarchical) approach to loading classes. The search is carried out within a small set of modules. The question arises, how can the environment know which modules to search for?

It is solved, unfortunately, only by explicitly listing the module dependencies. To do this, in the deployed war, the Dependencies field in which its dependencies are listed is appended to its manifest.

By its name, the server finds the xml describing this module: a set of jar-files included in it, and the modules on which this one depends.

Use maven

When maven is used to build such an approach to providing packages, some dependencies in pom.xml should be declared provided. For example, when using slf4j, it will look like this:

<dependencides> <dependecy> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.6.1</version> <scope>provided</scope> </dependecy> <!-- ... --> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <configuration> <archive> <manifestEntries> <Dependencies>org.slf4j</Dependencies> </manifestEntries> </archive> </configuration> </plugin> <!-- ... --> </plugins> </build> 


Debugging in IntelliJ IDEA

Despite the beauty of this IDE, there are often unpleasant flaws in it. For example, when interacting with maven. When you try to debug a project that uses the config from the previous paragraph, it turns out that the artifact collected by maven is working correctly,
And at deploe from Idea NoClassDefFoundError takes off. This is due to the fact that IDEA does not use data from pom.xml, but generates its MANIFEST.MF, which is detached by the absence of the Dependencies item.
You can bypass this behavior by creating your own manifest of this type:

Manifest-Version: 1.0
Dependencies: org.slf4j


The obvious disadvantage of this workaround is duplication of information about dependencies in two places.

Source: https://habr.com/ru/post/140133/


All Articles