This tutorial provides a low-level view of JBoss AS 7 class loading mechanism which is based on the JBoss Modules project.
The Java Classloader is a part of the Java Runtime Environment that dynamically loads Java classes into the Java Virtual Machine. However there are some various ways in which the classloading process can end up not working, we can enumerate:
– A developer or deployer of a Java application has accidentally made two different versions of a library available to the system. This will not be considered an error by the system. Rather, the system will load classes from one or the other library. Adding the new library to the list of available libraries instead of replacing it, may see the application still behaving as though the old library is in use, which it may well be.
– Two libraries (or a library and the application) require different versions of the same third library. If both versions of the third library use the same class names, there is no way to load both versions of the third library with the same classloader.
– The most complex JAR hell problems arise in circumstances that take advantage of the full complexity of the classloading system. A Java program is not required to use only a single “flat†classloader, but instead may be composed of several (potentially very many) nested, cooperating classloaders. Classes loaded by different classloaders may interact in complex ways not fully comprehended by a developer, leading to inexplicable errors or bugs.
Class loading is considerably different to previous versions of JBoss AS. Class loading is based on the JBoss Modules project. Instead of the more familiar hierarchical class loading environment, AS7′s class loading is based on modules that have to define explicit dependencies on other modules. Deployments in AS7 are also modules, and do not have access to classes that are defined in jars in the application server unless an explicit dependency on those classes is defined.
How it works?
To understand how it works internally we use JArchitect and CQLinq queries to query the JBoss-modules code base. CQlinq is a powerful query language based on linq to query the code base, you can try its possibilities from “Queries and Rules Edit†view.
To start let’s search what happens when the main method is invoked by executing the following CQLinq query:
from m in Methods where m.IsUsedBy (“org.jboss.modules.Main.main(String[])â€)
select new { m, m.NbBCInstructions }
The java.lang.Thread.setContextClassLoader() method is invoked to set the context ClassLoader. The context ClassLoader can be set when a thread is created, and allows the creator of the thread to provide the appropriate class loader to code running in the thread when loading classes and resources.
Let’s discover the class loaders defined by JBoss:
from t in Types where !t.IsThirdParty
let depth0 = t.DepthOfDeriveFrom(“java.lang.ClassLoaderâ€)
where depth0 >= 0 orderby depth0
select new { t, depth0,IsAbstract=t.IsAbstract }
There are two classes inheriting from ClassLoader but only ModuleClassLoader could be instantiated. ModuleClassLoader inherits from ConcurrentClassLoader which inherit from SecureClassLoader from the jdk. ConcurrentClassLoader is useful to treat dead lock problems. Here is where the ClassModuleLoader is instantiated:
from m in Methods
let depth0 = m.DepthOfCreateA(“org.jboss.modules.ModuleClassLoaderâ€)
where depth0 == 1
select new { m, depth0 }
What’s interesting is that each module has its own class loader, different version of the same jar could be loaded for different modules loaded.
What’s exactly a module?
To understand what the module is, let’s discover how a module is described, and here’s an example of a module descriptor:
<module xmlns=â€urn:jboss:module:1.1″ name=â€org.jboss.mscâ€>
<main-class name=â€org.jboss.msc.Versionâ€/>
<properties>
<property name=â€my.property†value=â€fooâ€/>
</properties>
<resources>
<resource-root path=â€jboss-msc-1.0.1.GA.jarâ€/>
</resources>
<dependencies>
<module name=â€javax.apiâ€/>
<module name=â€org.jboss.loggingâ€/>
<module name=â€org.jboss.exampleâ€>
<imports>
<exclude-set>
<path name=â€org.jboss.example.testsâ€/>
</exclude-set>
</imports>
</module>
<!– Optional deps –>
<module name=â€javax.inject.api†optional=â€trueâ€/>
<module name=â€org.jboss.threads†optional=â€trueâ€/>
<module name=â€org.jboss.vfs†optional=â€trueâ€/>
</dependencies>
</module>
A module descriptor is an XML file which describes the structure, content, dependencies, filtering, and other attributes of a module. ConcreteModuleSpec is the class from JBoss containing these infos. And here’s the dependency graph showing all classes used by it.
A resource is described by the ResourceLoaderSpec, a dependency by DependencySpec and the properties by a Map. Let’s describe each section of the module descriptor.
Main Class
A module which is defined with a “main-class†element is said to be executable. In other words, the module name can be listed on the command line, and the standard static main(String[]) method in the named module’s “main-class†will be loaded and executed.
Let’s discover all the methods using directly or indirectly the ConcreteModuleSpec.mainClass field:
from m in Methods
let depth0 = m.DepthOfIsUsing(“org.jboss.modules.ConcreteModuleSpec.mainClassâ€)
where depth0 >= 0 orderby depth0
select new { m, depth0 }
Many methods use it specially loadModule which needs to execute it if it’s assigned.
Resources
In order for a module to actually have content, you must define the “resources†element with at least one resource root.
A resource root is a specification of a location where the class loader for a module will look for classes and resources. Each module has zero or more resource roots, though most regular modules will contain exactly one, which refers to the JAR file with the module’s content.
A resource is defined in the code base by the interface Resource, Let’s search for all classes implementing it.
from t in Types where t.Implement (“org.jboss.modules.Resourceâ€)
select new { t, t.NbBCInstructions }
The resource could be defined by a jar, a path or a URL path containing the jars.
Properties:
The modules API exposes a method which can read property (string key-value pair) values from a module. To specify values for these properties you use the “properties†element which can contain zero or more “property†elements.
dependencies:
A module may express one or more dependencies on other module(s) via the “dependencies†element.
A dependency is defined by the Dependency class which is an abstract class, here are all dependencies classes inheriting from it.
Let’s search for all methods using directly the Dependency class.
from m in Methods where m.IsUsing (“org.jboss.modules.Dependencyâ€)
select new { m, m.NbBCInstructions }
The methods addPaths and addExportedPaths treat all the dependencies specified in the module descriptor, and we can search for all types used by addPaths.
from t in Types where t.IsUsedBy (“org.jboss.modules.Module.addPaths(Dependency[],Map,FastCopyHashSet,FastCopyHashSet,FastCopyHashSet,Set)â€)
select new { t, t.NbBCInstructions }
As shown in the dependency graph this method uses the dependencies and also the filters specified in the module descriptor to assign all possible module dependencies.
Modules management.
To manage the modules from a console for example, JMX is the appropriate solution in the java world.
Java Management Extensions (JMX) is a Java technology that supplies tools for managing and monitoring applications, system objects, devices (e. g. printers) and service oriented networks. Those resources are represented by objects called MBeans (for Managed Bean). In the API, classes can be dynamically loaded and instantiated. Managing and monitoring applications can be designed and developed using the Java Dynamic Management Kit.
JBoss-modules conatins the package org.jboss.modules.management which contains the ModuleLoaderMXBean, this interface defines methods to get all interesting infos for a module, and we can also unload the module.
This interface is implemented by the org.jboss.modules.ModuleLoader.MXBeanImpl class.
Conclusion
JBoss Modules is a standalone implementation of a modular (non-hierarchical) class loading and execution environment for Java. In other words, rather than a single class loader which loads all JARs into a flat class path, each library becomes a module which only links against the exact modules it depends on, and nothing more. It implements a thread-safe, fast, and highly concurrent delegating class loader model.
Thanks to lahlali issam for providing the material for this tutorial. You can evaluate a free copy of JArchitect here.