Understanding J2EE Application Server ClassLoading Architectures

The packaging mechanisms defined in Chapter 8 of the J2EE 1.3 specification provide a framework for pulling together all the pieces of a J2EE application. However, application server vendors are free to design a proprietary class loading hierarchy for obtaining the classes and resources found in an application. A class loading hierarchy is typically used to enable features such as hot redeployment and application independence.

Introduction

The packaging mechanisms defined in Chapter 8 of the J2EE 1.3 specification provide a framework for pulling together all the pieces of a J2EE application. However, application server vendors are free to design a proprietary class loading hierarchy for obtaining the classes and resources found in an application. A class loading hierarchy is typically used to enable features such as hot redeployment and application independence.

Understanding the class loading architectures of major application server vendors helps J2EE developers design application packaging structures that are both portable and efficient. After a brief primer on the basics of class loading, the class loading hierarchies of three major application servers (BEA WebLogic 6.1 SP2, IBM WebSphere 4.0, and HP-AS 8 Maintenance Pack 3) are presented. The discussion is limited to J2EE application modules (.ear), EJB modules (.jar) and web application modules (.war). A familiarity with J2EE packaging mechanisms (.ear, .war, and .jar) is assumed; please see the References section for introductory material.

After reading this article, J2EE developers will have a better understanding of how classloading architectures can affect J2EE packaging decisions. As an added bonus, classloading architecture knowledge can also be enormously beneficial when debugging the common ClassNotFoundException often generated by J2EE application servers.

Class Loading Basics

Typically class loaders are arranged in a parent/child hierarchy. When a class loading request is presented to a class loader, it first asks its parent class loader to fulfill the request. The parent, in turn, asks its parent for the class until the request reaches the top of the hierarchy. If the class loader at the top of the hierarchy cannot fulfill the request, then the child class loader that called it is responsible for loading the class. If the child is also unable to load the class, the request continues back down the hierarchy until a class loader fulfills it or a ClassNotFoundException is produced by the class loader at the bottom of the hierarchy.


Figure 1 illustrates a basic class loading hierarchy. Note that a class loaded at a given level in the hierarchy may not reference any classes loaded at a lower level in the hierarchy. Stated another way, a class loader has no visibility into classes loaded by its descendants. In figure 1, if class Foo is loaded by class loader B, and Foo depends on class Baz, then class Baz must be loadable by either class loader A or B. If Baz is only visible to class loader C or D, then a ClassNotFoundException will occur.

If the class Bar is visible to two sibling class loaders (e.g., C and D in Figure 1) but not to their parent class loaders, and if a request for Bar is sent to both sibling class loaders, then each class loader will load its own version of the class. Instances of Bar based on class loader C will not be type compatible with instances based on class loader D. This fundamental fact can lead to confusing bugs especially when the class loader hierarchy is not well understood. See the References section for pointers to specific discussions of class loading oddities (e.g., multiple singleton instances).

Section 8.1.1.2 of the J2EE 1.3 specification mandates explicit support for the bundling of dependent .jar files via the Extension Mechanism Architecture (see the References section). Application servers must load dependent .jar files listed in the Manifest Class-Path entry of a primary .jar file (typically an EJB .jar). This requirement is not mandated for .ear or .war files. The extension mechanism is a valuable technique that should not be overlooked when packaging an application. Whenever possible, be sure to investigate and understand exactly which class loader is used to load dependent jar files.

Programmatically uncovering the class loader hierarchy is a simple exercise, but the resulting output can help identify how classes are being loaded. The code below will emit the class loading hierarchy from the perspective of a given class.

 ClassLoader classLoader = getClass().getClassLoader(); // Implies that we're at the top of the hierarchy when null. while (classLoader != null) { System.out.println("Class/Method Name Here: parent classLoader == " + classLoader.toString()); // Note that getParent() may require opening up the // security settings in the JVM. classLoader = classLoader.getParent(); } System.out.println("Class/Method Name Here: parent classLoader == null");

J2EE application servers typically make use of at least two levels of class loaders. Without a firm grasp of how classes are loaded in a given application server, difficult bugs can arise and confusing runtime errors may occur. With this basic background in place, let's look at how three major application servers choose to implement their class loading hierarchy.

WebLogic 6.1 with Service Pack 2

When deploying a J2EE application in .ear form with WebLogic 6.1 SP2, two or more new class loaders are created below the standard system class loaders for each J2EE application. Figure 2 shows the resulting class loader architecture. One EJB class loader is created as a child of the system class loaders. It is responsible for loading all EJB .jar classes for all EJB .jar files in the .ear. One web application class loader is created for each .war in the .ear, and each of the web application class loaders is a child of the EJB class loader. (Note: The WebLogic 6.1 documentation indicates that only one class loader is created for all .wars in the .ear; this is not accurate.) The web application class loaders are responsible for loading the classes and jars in the WEB-INF/classes and WEB-INF/lib directories in the corresponding .war.

As of Service Pack 2 of WebLogic 6.1 (WebLogic issue 056911 -- see the References section below), .jar files listed in a Manifest Class-Path entry are loaded by the application's EJB class loader. This applies to Manifest Class-Path entries found in EJB .jar files and web application .war files within the .ear. Note that the Manifest Class-Path approach is only supported when deploying components within an .ear.

One advantage of this class loading architecture is the automatic availability of all EJB classes from the web application class loaders. However, classes found in the WEB-INF/classes or WEB-INF/lib directories of a .war are not available to any EJB classes.

If .war or .jar files are deployed into WebLogic 6.1 SP2 independently (i.e., not within an .ear), then they are considered separate applications and will effectively have sibling class loaders. This implies that an independent .war no longer has default access to EJB classes.

WebSphere 4.0

The WebSphere 4.0 class loading architecture is relatively complex compared to WebLogic 6.1. The WebSphere documentation explains the necessary details in terms of classpaths rather than class loaders; however, the References section below contains a link to a classloader-based description of the same material.

WebSphere 4.0 defines the concept of an "isolation mode". A particular isolation mode alters the view that class loaders have into other class loaders. Four isolation modes exist in WebSphere 4.0:

  • Module: One class loader is created for each module in an .ear. A module is defined as a web app .war, an EJB .jar, or a .jar referenced from the Manifest Class-Path of a .war or .jar. The logical class loader hierarchy is formed by dependencies specified in the Manifest Class-Path attributes of the modules. For an application with two .war files, two EJB .jar files, and two common .jar utility libraries listed in Manifest Class-Path attributes, six class loaders would be created.
  • Application: This mode allows all class loaders associated with a given J2EE application .ear to have access to all other class loaders within the application. Logically it is like having one class loader for the entire application.
  • Compatibility: This mode is intended to provide backward compatibility with the class loading semantics of WebSphere 3.5.x and 3.0.2.x. This mode is similar to WebLogic 6.1 in that all web application .war modules have visibility into all EJB .jar modules, and all EJB .jar modules can see all other EJB .jar modules.
  • Server: This mode is logically equivalent to having one class loader for all applications in the entire app server.

Figure 3 shows the typical class loading architecture in Module mode. Notice that all the module class loaders are siblings in the hierarchy. However, in WebSphere 4.0 this does not imply that they are unaware of one another. A class loader grouping mechanism is used to ensure the appropriate class loading hierarchy semantics. For example, if EJB1 lists common.jar in its Manifest Class-Path attribute, common.jar will be loaded in a separate sibling class loader. However, EJB1 logically acts like it is a child of the common.jar class loader. The grouping mechanism is used to obtain the appropriate semantics for all four isolation modes; however, the details of exactly how this mechanism works is not exposed in the WebSphere documentation.


The WebSphere 4.0 documentation highly recommends using the Module isolation mode in conjunction with Manifest Class-Path entries. This combination is advertised as the most portable approach.

It is interesting to note that both WebSphere 4.0 and WebLogic 6.1 SP2 support Manifest Class-Path entries in .jar and .war files; however, the same .ear file may run fine in one and not the other. This is because WebLogic 6.1 SP2 loads a .jar file specified in any Manifest Class-Path (.jar or .war) into the EJB class loader for the application. As long as one .jar or .war in the application specifies the dependent .jar in its Manifest Class-Path, then all other .jar and .war files can successfully reference it without explicitly listing it in their Manifest Class-Paths. In contrast, WebSphere 4.0 requires that such Manifest Class-Path references be explicitly listed in every J2EE module (.war or .jar) that needs them.

Section 8.1.1.2 of the J2EE 1.3 specification states that Manifest Class-Path support is only required of .jar files. Supporting the technique in .war files can be seen as a non-standard extension. Indeed, the J2EE 1.3.1 reference implementation does not pay attention to Manifest Class-Path entries in .war files. In many cases, however, support for Manifest Class-Path entries in .war files can be extremely helpful in designing a clean .ear package structure. However, the non-standard (and hence non-portable) nature of this technique must be factored into the decision to use it.

HP-AS 8 Maintenance Pack 3

The class loading architecture of HP-AS 8 most resembles WebSphere 4.0, although the logical semantics are closer to WebLogic 6.1 SP2. Figure 4 shows the HP-AS 8 approach.


The library class loader is the parent of all application class loaders. The classpath it searches is specified by entries in the proprietary application-classloader-service-config.xml file typically found in <HP-AS-HOME>/config/hpas. An entry in this file looks like this:

 <library name="common" url="file:///d:/lib/common.jar"/>

One application class loader is created as a child of the library class loader for each J2EE application deployed in HP-AS 8. One EJB class loader is created as a child of the application class loader. The EJB class loader is responsible for loading all classes within all EJB .jar archives in the J2EE application. One web application class loader is created as a child of the application class loader for each web application archive in the J2EE application. The fact that each .war gets its own class loader allows web application independence to be achieved within an application. When J2EE components are deployed individually (i.e., not within an .ear), they are automatically associated with a default application and its application classloader.

The application class loader is unique in that it does not load classes. Instead it delegates that responsibility to its children in the following order: connector classloader (not covered here), EJB classloader, and web application classloader(s). Experiments show that classes contained in an EJB .jar are visible to other EJB .jars and all web application class loaders. However, classes contained in a web application archive are not visible to the EJB class loader or to other web application archive class loaders. These logical class loading semantics are similar to WebLogic 6.1 SP2.

As of maintenance pack 3, the HP-AS 8 application server does not support Manifest Class-Path extension mechanism for structuring dependencies. However, this feature is slated for an upcoming maintenance pack. For common utility .jar files normally placed in the Manifest Class-Path on other application servers, several options are available. Placing them in an EJB jar will provide appropriate visibility as will loading them into the library class loader via the application-classloader-service-config.xml file.

Conclusion

Understanding the class loading architectures of a variety of application servers demystifies the facts surrounding how the components of a particular J2EE application are loaded. Armed with this information, J2EE developers can design portable J2EE packaging structures or at least understand the tradeoffs when using proprietary techniques. This is particularly important for J2EE component and framework providers who must take on the extra task of shipping their components in the most portable manner.


 

References

The J2EE 1.3 Specification
http://java.sun.com/j2ee/download.html#platformspec

The Extension Mechanism Architecture (Manifest Class-Path)
http://java.sun.com/j2se/1.4/docs/guide/extensions/spec.html

WebLogic 6.1 packaging and class loader documentation
http://java.sun.com/j2se/1.4/docs/guide/extensions/spec.html

WebLogic 6.1 Service Pack 2 release notes issue 056911 (Class-Path in .war files):
http://e-docs.bea.com/wls/docs61/notes/bugfixes2.html

WebSphere 4.0 documentation - See section 6.4.1.
http://e-docs.bea.com/wls/docs61/notes/bugfixes2.html

Additional WebSphere 4.0 classloading material
http://publib.boulder.ibm.com/was400/40/AE/english/docs/servmojv.html

WebSphere 4.0 class loading article (search www.ibm.com for
"J2EE Class Loading Demystified" by Tim deBoer and Gary Karasiuk)
http://www.ibm.com/

HP-AS 8 documentation (look in chapter 3 of the Developer's Guide for a discussion of class loading)
http://www.bluestone.com/products/hp-as/default.htm

Two class loading articles by Tyler Jewell
http://www.onjava.com/lpt/a/onjava/2001/06/26/ejb.html
http://www.onjava.com/lpt/a/onjava/2001/07/25/ejb.html

An excerpt from Chapter 24 of "Professional Java Server Programming, J2EE 1.3 Edition"
(Wrox Press) that describes J2EE packaging and class loading
/articles/article.tss?l=J2EE-Deployment

An article on type-safe enums in multiple class loaders:
http://www.javaworld.com/javaworld/javatips/jw-javatip122.html

Dig Deeper on Core Java APIs and programming techniques