It was almost a year ago that Mark Reinhold (one of the top Java engineers over at Sun/Oracle) announced
The classpath is dead! at JavaONE, accompanied by a series of blog posts like this one, proclaiming that the future of Java is a modular one. In the mean time, the JDK 7 timeline has slipped dramatically and we may not see modules in Java proper until 2012 or later. All the while, the folks on JSR 294 have stalled, started, and stalled again, slowly inching their way towards a tightly-Java-integrated modularization standard, possibly requiring significant language, bytecode, and packaging changes to support it.
I've long maintained that it would take far less than this to introduce a solid, usable modularity standard. And as part of our JBoss AS 7 proof-of-concept work, we've proven it with the creation of JBoss Modules.
If you haven't been following the developments around JDK 7, you may not even be aware of what you're missing.
A module is any collection of classes and resources, associated with a single class loader. Modules may express a dependency on other modules. The exported classes and resources from these dependencies are visible to classes in the dependent module. Visibility is the ability of a class from one class loader to
see a class from another class loader. To export a class or resource means to make such a class or resource visible to dependents.
So what a module system provides is a way to package up classes and resources into modules, and establish a graph, at run time, of class loaders such that all the expressed dependencies are satisfied.
The traditional method of running an application in Java uses the well-known
classpath mechanism. This basically creates a single application class loader with all those JARs' resources concatenated together in one big blob.
Now imagine you have a very, very large and complex application with dozens of JARs. Imagine that some of those JARs are not used all the time, or that some of those JARs represent multiple, conflicting versions of the same classes and packages due to conflicting dependencies. This problem, and other issues along these lines, are known popularly as Jar Hell.
Modules can greatly alleviate this problem. When all JARs are bundled as modules, a JAR will never
see a conflicting version of a dependency class, or pick up resources from other JARs inadvertently. Also, a module which is never used will never be loaded which can improve startup time of large applications.
JBoss Modules is a standalone module system for Java 6 and up. It supports the following features (and more):
- An memory-efficient, high-performance, concurrent/thread-safe delegating class loader implementation, capable of loading any class or resource in O(1) time
- An extensible module loader system which allows users to plug in alternative module definition/loading strategies
- An easy-to-use bundled local module loader, which loads modules (packaged as standard JARs or as exploded directories) from the filesystem in a simple, predictable structure (think Maven, but simpler)
- An easy bootstrap process (see below)
- A useful runtime API for loading modules, getting a class loader for modules, creating modules at run-time, extending the JDK service loader mechanism to be module-aware, and more
- Management of platform-specific native code
A modularized program is started like this:
java -jar jboss-modules.jar -mp path/to/modules my.main.module.name
In your module path (
-mp) you specify the root directory (or directories) which will be searched by the default module loader for module definitions. A module is defined using a simple XML descriptor, like this:
<module xmlns="urn:jboss:module:1.0" name="org.jboss.msc"> <main-class name="org.jboss.msc.Version"/> <resources> <resource-root path="jboss-msc-1.0.0.Beta3.jar"/> </resources> <dependencies> <module name="org.jboss.logging"/> <!-- 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>
There is a full schema bundled in jboss-modules.jar for this descriptor format, so integration with your favorite IDE is easy. There are also many extended capabilities available which allow tight control over what packages are exported or imported, and you can also selectively exclude content from your resource JARs (making it even easier to use prepackaged JARs).
This simple module system has several advantages over JSR 294 as it stands today.
- It's available now. There is no telling when JDK modules will become available - maybe in Java 7 in 2012, maybe in Java 8 or later. This is a project you can use - and contribute to - today.
- No invasive language, bytecode, or compiler changes are needed, and no JCP approval is necessary.
- As things stand today, JBoss Modules should be compatible with JSR 294, and we will strive to maintain compatibility if and when Jigsaw solidifies and becomes part of OpenJDK.
- It is much simpler; one JAR is all that is needed to get your modular application off the ground.
- It is minimal: there is no services layer, or any other higher level functions that OSGi provides. It does exactly one thing, and it does it well.
- At the same time, it is very powerful, and could form the basis of a class loading framework which an OSGi implementation could use (more on this in the future, stay tuned!).
JBoss Modules is available now via Maven as
org.jboss.modules:jboss-modules. There is also a JIRA Instance available for reporting problems. Discussion relating to Modules in AS 7 happens here or on #jboss-msc on FreeNode IRC (join via webchat with your registered nickname). The source code is hosted on GitHub.
So... what are you waiting for?