WebSphere Application Server V7: Understanding Class Loaders

Download WebSphere Application Server V7: Understanding Class Loaders

Preview text

Chapter 13 of WebSphere Application Server V7
Administration and Configuration Guide, SG24-7615
WebSphere Application Server V7: Understanding Class Loaders
Understanding how the Java™ and WebSphere® class loaders work is critical to packaging and deploying Java EE5 applications. Failure to set up the class loaders properly most likely results in a cascade of the infamous class loading exceptions (such as ClassNotFoundException) when trying to start your application. In this chapter we explain class loaders and how to customize the behavior of the WebSphere class loaders to suit your particular application’s requirements. The chapter concludes with an example designed to illustrates these concepts. We cover the following topics:
“A brief introduction to Java class loaders” on page 2 “WebSphere class loaders overview” on page 6 “Configuring WebSphere for class loaders” on page 10 “Class loader viewer” on page 17 “Learning class loaders by example” on page 18

© Copyright IBM Corp. 2009. All rights reserved.


A brief introduction to Java class loaders
Class loaders enable the Java virtual machine (JVM™) to load classes. Given the name of a class, the class loader locates the definition of this class. Each Java class must be loaded by a class loader.
When you start a JVM, you use three class loaders: the bootstrap class loader, the extensions class loader, and the application class loader:
The bootstrap class loader is responsible for loading only the core Java
libraries in the Java_home/jre/lib directory. This class loader, which is part of the core JVM, is written in native code.
The extensions class loader is responsible for loading the code in the
extensions directories (Java_home/jre/lib/ext or any other directory specified by the java.ext.dirs system property). This class loader is implemented by the sun.misc.Launcher$ExtClassLoader class.
The application class loader is responsible for loading code that is found on
java.class.path, which ultimately maps to the system CLASSPATH variable. This class loader is implemented by the sun.misc.Launcher$AppClassLoader class.
The parent-delegation model is a key concept to understand when dealing with class loaders. It states that a class loader delegates class loading to its parent before trying to load the class itself. The parent class loader can be either another custom class loader or the bootstrap class loader. But what is very important is that a class loader can only delegate requests to its parent class loader, never to its child class loaders (it can go up the hierarchy but never down).
The extensions class loader is the parent for the application class loader. The bootstrap class loader is the parent for the extensions class loader. The class loaders hierarchy is shown in Figure 1 on page 3.
If the application class loader needs to load a class, it first delegates to the extensions class loader, which, in turn, delegates to the bootstrap class loader. If the parent class loader cannot load the class, the child class loader tries to find the class in its own repository. In this manner, a class loader is only responsible for loading classes that its ancestors cannot load.
2 WebSphere Application Server V7: Understanding Class Loaders

Bootstrap Class Loader
Extensions Class Loader
Application Class Loader
Figure 1 Java class loaders hierarchy This behavior can lead to some interesting problems if a class is loaded from a class loader that is not on a leaf node in the class loader tree. Consider Example 1. A class called WhichClassLoader1 loads a class called WhichClassLoader2, in turn invoking a class called WhichClassLoader3. Example 1 WhichClassLoader1 and WhichClassLoader2 source code public class WhichClassLoader1 {
public static void main(String[] args) throws javax.naming.NamingException {
// Get classpath values String bootClassPath = System.getProperty("sun.boot.class.path"); String extClassPath = System.getProperty("java.ext.dirs"); String appClassPath = System.getProperty("java.class.path"); // Print them out System.out.println("Bootstrap classpath =" + bootClassPath + "\n"); System.out.println("Extensions classpath =" + extClassPath + "\n"); System.out.println("Application classpath=" + appClassPath + "\n"); // Load classes Object obj = new Object();
WebSphere Application Server V7: Understanding Class Loaders 3

WhichClassLoader1 wcl1 = new WhichClassLoader1(); WhichClassLoader2 wcl2 = new WhichClassLoader2();
// Who loaded what? System.out.println("Object was loaded by "
+ obj.getClass().getClassLoader()); System.out.println("WCL1 was loaded by "
+ wcl1.getClass().getClassLoader()); System.out.println("WCL2 was loaded by "
+ wcl2.getClass().getClassLoader());
wcl2.getTheClass(); } } ======================================================================= === public class WhichClassLoader2 {
// This method is invoked from WhichClassLoader1 public void getTheClass() {
WhichClassLoader3 wcl3 = new WhichClassLoader3(); System.out.println("WCL3 was loaded by "
+ wcl3.getClass().getClassLoader()); } }
If all WhichClassLoaderX classes are put on the application class path, the three classes are loaded by the application class loader, and this sample runs just fine. Now suppose that you package the WhichClassLoader2.class file in a JAR file that you store under Java_home/jre/lib/ext directory. You can see the output in Example 2.
Example 2 NoClassDefFoundError exception trace
Bootstrap classpath =C:\WebSphere\AppServer\java\jre\lib\vm.jar;C:\WebSphere\AppServer\java \jre\lib\core.jar;C:\WebSphere\AppServer\java\jre\lib\charsets.jar;C:\W ebSphere\AppServer\java\jre\lib\graphics.jar;C:\WebSphere\AppServer\jav a\jre\lib\security.jar;C:\WebSphere\AppServer\java\jre\lib\ibmpkcs.jar; C:\WebSphere\AppServer\java\jre\lib\ibmorb.jar;C:\WebSphere\AppServer\j ava\jre\lib\ibmcfw.jar;C:\WebSphere\AppServer\java\jre\lib\ibmorbapi.ja r;C:\WebSphere\AppServer\java\jre\lib\ibmjcefw.jar;C:\WebSphere\AppServ er\java\jre\lib\ibmjgssprovider.jar;C:\WebSphere\AppServer\java\jre\lib \ibmjsseprovider2.jar;C:\WebSphere\AppServer\java\jre\lib\ibmjaaslm.jar ;C:\WebSphere\AppServer\java\jre\lib\ibmjaasactivelm.jar;C:\WebSphere\A ppServer\java\jre\lib\ibmcertpathprovider.jar;C:\WebSphere\AppServer\ja
4 WebSphere Application Server V7: Understanding Class Loaders

va\jre\lib\server.jar;C:\WebSphere\AppServer\java\jre\lib\xml.jar Extensions classpath =C:\WebSphere\AppServer\java\jre\lib\ext Application classpath=.
Exception in thread "main" java.lang.NoClassDefFoundError: WhichClassLoader3
at java.lang.J9VMInternals.verifyImpl(Native Method) at java.lang.J9VMInternals.verify(J9VMInternals.java:59) at java.lang.J9VMInternals.initialize(J9VMInternals.java:120) at WhichClassLoader1.main(WhichClassLoader1.java:17)
As you can see, the program fails with a NoClassDefFoundError exception, which might sound strange because WhichClassLoader3 is on the application
class path. The problem is that it is now on the wrong class path.
What happened was that the WhichClassLoader2 class was loaded by the extensions class loader. In fact, the application class loader delegated the load of the WhichClassLoader2 class to the extensions class loader, which in turn delegated the request to the bootstrap class loader. Because the bootstrap class loader could not find the class, the class loading control was returned to the extensions class loader. The extensions class loader found the class on its class path and loaded it.
Now, when a class has been loaded by a class loader, any new classes that the class needs reuse the same class loader to load them (or goes up the hierarchy according to the parent-delegation model). So when the WhichClassLoader2 class needed to access the WhichClassLoader3 class, it is the extensions class loader that first gets the request to load it. The extensions class loader first delegates the request to the Bootstrap class path, which cannot find the class, and then tries to load it itself but does not find it either because WhichClassLoader3 is not on the extensions class path but on the application classpath. And because the extensions class loader cannot delegate the request to the application class loader (a delegate request can only go up the hierarchy, never down), a NoClassDefFoundError exception is thrown.
Note: Remember that developers very often also load property files through the class loader mechanism using the following syntax:
Properties p = new Properties(); p.load(MyClass.class.getClassLoader().getResourceAsStream("myApp.properties"));
This means, if the class MyClass is loaded by the extensions class loader and the myApp.properties file is only seen by the application class loader, the loading of the property file fails.
WebSphere Application Server V7: Understanding Class Loaders 5

WebSphere class loaders overview

Note: Keep in mind when reading the following discussion that each JVM has its own set of class loaders. In a WebSphere environment hosting multiple application servers (JVMs), this means the class loaders for the JVMs are completely separate even if they are running on the same physical machine.
Also note that the JVM uses class loaders called the extensions and application class loaders. As you will see, the WebSphere runtime also uses class loaders called extensions and application class loader, but despite their names, they are not the same as the JVM ones.
WebSphere provides several custom delegated class loaders, as shown in Figure 2.

Java class loaders (Bootstrap, Extensions, Application)
WebSphere Extensions class loader (3rd party code, JDBC drivers etc.)

WebSphere Application Server OSGi Runtime

Application class loader (EJBs, RARs, Utility JARs)

Application class loader (EJBs, RARs, Utility JARs)

WAR class loader

WAR class loader

WAR class loader

WAR class loader

Figure 2 WebSphere class loaders hierarchy
The top box represents the Java (bootstrap, extensions, and application) class loaders. WebSphere loads just enough here to get itself bootstrapped and initialize the WebSphere extensions class loader.

6 WebSphere Application Server V7: Understanding Class Loaders

WebSphere extensions class loader
The WebSphere extensions class loader is where WebSphere itself is loaded. In versions of WebSphere prior to V6.1, the runtime was loaded by this single class loader. However, beginning with V6.1, WebSphere is packaged as a set of OSGi bundles. Each OSGi bundle is loaded separately by its own class loader. This network of OSGi class loaders is then connected to the extensions class loader and the rest of the class loader hierarchy through an OSGi gateway class loader.
Despite this architectural change in the internals of how WebSphere loads its own classes, there is no behavioral change as far as your applications are concerned. They still have the same visibility, and the same class loading options still exist for your application.
Prior to V6.1, the WebSphere runtime classes files were stored in the classes, lib, lib\ext, and installedChannels directories in the install_root directory. Because of the OSGi packaging, these directories no longer exist and the runtime classes are now stored in the install_root\plugins directory.
The class path used by the extensions class loader is retrieved from the ws.ext.dirs system property, which is initially derived from the WAS_EXT_DIRS environment variable set in the setupCmdLine script file. The default value of ws.ext.dirs is displayed in Example 3.
Example 3 Default value of ws.ext.dirs
SET WAS_EXT_DIRS=%JAVA_HOME%\lib;%WAS_HOME%\classes;%WAS_HOME%\lib;%WAS_HOM E%\installedChannels;%WAS_HOME%\lib\ext;%WAS_HOME%\web\help;%ITP_LOC%\p lugins\com.ibm.etools.ejbdeploy\runtime
Each directory listed in the ws.ext.dirs environment variable is added to the WebSphere extensions class loaders class path and every JAR file and ZIP file in the directory is added to the class path.
While the classes and installedChannels directories no longer exist in the install_root directory, the setupCmdLine script still adds them to the extensions class path. This means that if you have added your own JAR files to one of these directories in previous releases, you could create this directory and add your JAR files to it and they would still be loaded by the extensions class loader. However, this is not recommended and you should really try to migrate away from such a setup.
On the other hand, if you have developed Java applications that rely on the WebSphere JAR files that were in the install_root\lib directory prior to V6.1, you will need to modify your application to retain compatibility. WebSphere
WebSphere Application Server V7: Understanding Class Loaders 7

Application Server provides two thin client libraries designed specifically for such applications: one administrative client library and one Web services client library. These thin client libraries can be found in the install_root\runtimes directory:
com.ibm.ws.admin.client_7.0.0.jar com.ibm.ws.webservices.thinclient_7.0.0.jar
These libraries provide everything your application might need for connecting to and working with WebSphere. WebSphere Application Server V7 gives you the ability to restrict access to internal WebSphere classes so that your applications do not make unsupported calls to WebSphere classes not published in the official WebSphere Application Server API. This setting is an application server setting called Access to internal server classes.
The default setting is Allow, meaning that your applications can make
unrestricted calls to non-public internal WebSphere classes. This function is not
recommended and might be prohibited in future releases. Therefore, as an administrator, it is a good idea to switch this setting to Restrict to see if your applications still work. If they depend on non-public WebSphere internal classes, you will receive a ClassNotFoundException, and in that case you can switch back to Allow. Your developers should then try to migrate their applications so that they do not make unsupported calls to the WebSphere internal classes in order to retain compatibility with future WebSphere Application Server releases.
Application and Web module class loaders
Java EE 5 applications consist of five primary elements: Web modules, EJB™ modules, application client modules, resource adapters (RAR files), and utility JARs. Utility JARs contain code used by both EJBs and servlets. Utility frameworks such as log4j are good examples of a utility JAR.
EJB modules, utility JARs, resource adapter files, and shared libraries associated with an application are always grouped together into the same class loader. This class loader is called the application class loader. Depending on the class loader policy, this class loader can be shared by multiple applications (EARs), or be unique for each application, which is the default.
By default, Web modules receive their own class loader, a WAR class loader, to load the contents of the WEB-INF/classes and WEB-INF/lib directories. You can modify the default behavior by changing the application's WAR class loader policy. This policy setting can be found in the administrative console by selecting Applications → WebSphere enterprise applications → application_name → Class loading and update detection → WAR class loader policy. See Figure 3.
8 WebSphere Application Server V7: Understanding Class Loaders

Figure 3 WAR class loader policy
The default is set to Class loader for each WAR file in the application. This setting is called Module in previous releases and in the application deployment descriptor as viewed in Rational® Application Developer.
If the WAR class loader policy is set to Single class loader for application, the Web module contents are loaded by the application class loader in addition to the EJBs, RARs, utility JARs, and shared libraries. The application class loader is the parent of the WAR class loader. This setting is called Application in previous releases and in the application deployment descriptor as viewed in Rational Application Developer.
The application and the WAR class loaders are reloadable class loaders. They monitor changes in the application code to automatically reload modified classes. You can modify this behavior at deployment time.
WebSphere Application Server V7: Understanding Class Loaders 9

Handling JNI code
Because a JVM only has a single address space, and native code can only be loaded once per address space, the JVM specification states that native code can only be loaded by one class loader in a JVM.
This might cause a problem if, for example, you have an application (EAR file) with two Web modules that both need to load the same native code through a Java Native Interface (JNI™). Only the Web module that first loads the library will succeed.
To solve this problem, you can break out just the few lines of Java code that load the native code into a class on its own and place this file on WebSphere’s application class loader (in a utility JAR). However, if you deploy multiple such applications (EAR files) to the same application server, you have to place the class file on the WebSphere extensions class loader instead to ensure that the native code is only loaded once per JVM.
If the native code is placed on a reloadable class loader (such as the application class loader or the WAR class loader), it is important that the native code can properly unload itself should the Java code have to reload. WebSphere has no control over the native code, and if it does not unload and load properly, the application might fail.
If one native library depends on another one, things become even more complicated. For more details, search for Dependent native library in the Information Center.
Configuring WebSphere for class loaders
In the previous topic, you learned about WebSphere class loaders and how they work together to load classes. There are settings in WebSphere Application Server that allow you to influence WebSphere class loader behavior. This section discusses these options.
Application server class loader policies
For each application server in the system, the class loader policy can be set to Single or Multiple. These settings can be found in the administrative console by selecting Servers → Server Types → WebSphere application servers → server_name. See Figure 4.
10 WebSphere Application Server V7: Understanding Class Loaders

Preparing to load PDF file. please wait...

0 of 0
WebSphere Application Server V7: Understanding Class Loaders