Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Take Control of Class Loading in Java

By building a classloading component container framework that isolates Java class loading to a specified jar file, you can be confident that the runtime will load the component versions you expect.

ava's class loading framework is powerful and flexible. It allows applications to access class libraries without linking to static "include" files. Instead, it loads archive files containing library classes and resources from designated locations, such as directories and network locations defined by the CLASSPATH environment variable. The system resolves run-time references to classes and resources dynamically, which simplifies updates and version releases. Nevertheless, each library has its own set of dependencies—and it is up to developers and deployment personnel to make sure that their applications properly reference the correct versions. Sadly, the combination of the default class-loading system and specific dependencies can and does lead to bugs, system crashes, and worse.

This article proposes a container framework for class loading intended to resolve these issues.

The Java Classpath
Java relies on the environment property/variable, CLASSPATH, to designate the path that the runtime uses to search for classes and other resources, as they are needed. You define the CLASSPATH property by setting the CLASSPATH environment variable or using the Java command-line option, -classpath.

A Java runtime typically finds and loads classes in the following order:

  1. Classes in the list of bootstrap classes—These are classes that embody the Java platform, such as the classes in rt.jar.
  2. Classes that appear in the list of extension classes—These classes use the Extension Mechanism Framework to extend the Java platform, with archive files (.jar, .zip, etc.) located in the /lib/ext directory of the runtime environment.
  3. User classes—These are classes that do not use the extension mechanism architecture identified using the -classpath command-line option or the CLASSPATH environment variable.
Archives and the Classpath
An archive .jar or.zip file can include a manifest file containing entries that can be used to provide archive information, set archive properties, etc. The manifest can also extend the classpath by including an entry named Class-Path, which contains a list of archives and directories. JDK 1.3 introduced the Class-Path manifest entry for specifying optional jars and directories that load if needed. Here's an example Class-Path entry:

Class-Path: mystuff/utils.jar mystuff/logging.jar mylib/

Java provides an extensible model for designating the list of locations and files from which to load classes. However, some problems can arise, such as when a different version of a library exists on the classpath than an executing class expects.

Classpath Version Conflicts
The runtime identity of a class in Java is defined by its fully-qualified name (the package name prepended to the class name, sometimes known as the FQN), all appended to the ID of the classloader that loaded the class. Thus, each instance of a class loaded by multiple classloaders is regarded as a separate entity by the Java runtime. This means that the runtime can load multiple versions of the same class at any given time. This is a very powerful and flexible feature; however, the side effects can be confusing to a developer if not used intelligently.

Imagine, if you will, that you're developing an enterprise application that accesses data from multiple sources with similar semantics, such a file system and a database. Many systems of this type expose a data-access layer with data access objects (DAOs) that abstract the similar data sources. Now, imagine that you load a new version of a database DAO with a slightly different API to meet the demands of a new feature of a DAO client—but you still need the old DAO for other clients not ready for the new API. In typical runtime environments, the new DAO will simply replace the old version and all new instances will be created from the new version. However, if the update takes place without stopping the runtime environment (hot-loading) any already-existing instances of the old DAO will reside in memory alongside any instances of the new DAO as they are created. This is confusing at best. Even worse is the danger of a DAO client expecting to create an instance of the old version of the DAO, but actually getting an instance of the new version with the altered API. As you can see, this can present some interesting challenges.

To ensure stability and safety, calling code must be able to designate the exact version of a class that it intends to use. You can address this by creating a class-loading, component-container model and using some simple class-loading techniques.

Comment and Contribute





