We start off with an class loading introduction, in which we explain the concepts and give an example implementation of a custom class loader. Subsequently, we will see how to package enterprise applications and how the different class loaders, such as APP-INF/lib, bundled libraries, shared libraries, etcetera, work. Such that we can package our enterprise applications in an appropriate manner such that the used classes can be found and make ClassNotFoundExceptions and NoClassDefFoundError something of the past.

Class loading introduction

All class loaders except the bootstrap class loader have a parent class loader. Moreover, all class loaders are of type java.lang.ClassLoader. The most important aspect is to correctly set the parent class loader. The parent class loader is the class loader instance that loaded that class loader (a class loader is itself a class).

Loading classes and interfaces

Loading refers to the process of finding the binary form of a class or interface type with a particular name, perhaps by computing it on the fly, but more typically by retrieving a binary representation previously computed from source code by a compiler, and constructing, from that binary form, a Class object to represent the class or interface. The loading process is implemented by the class ClassLoader and its subclasses. Different subclasses of ClassLoader may implement different loading policies. In particular, a class loader may cache binary representations of classes and interfaces, prefetch them based on expected usage, or load a group of related classes together. These activities may not be completely transparent to a running application if, for example, a newly compiled version of a class is not found because an older version is cached by a class loader. It is the responsibility of a class loader, however, to reflect loading errors only at points in the program where they could have arisen without prefetching or group loading.

Linking of classes and interfaces

Linking is the process of taking a binary form of a class or interface type and combining it into the runtime state of the Java virtual machine, so that it can be executed. A class or interface type is always loaded before it is linked. Three different activities are involved in linking: verification, preparation, and resolution of symbolic references:

  • Verification of the binary representation – Verification ensures that the binary representation of a class or interface is structurally correct. For example, it checks that every instruction has a valid operation code; that every branch instruction branches to the start of some other instruction, rather than into the middle of an instruction; that every method is provided with a structurally correct signature; and that every instruction obeys the type discipline of the Java virtual machine language.
  • Preparation of a class or interface type – Preparation involves creating the static fields (class variables and constants) for a class or interface and initializing such fields to the default values. This does not require the execution of any source code; explicit initializers for static fields are executed as part of initialization, not preparation. Implementations of the Java virtual machine may precompute additional data structures at preparation time in order to make later operations on a class or interface more efficient. One particularly useful data structure is a “method table” or another data structure that allows any method to be invoked on instances of a class without requiring a search of superclasses at invocation time.
  • Resolution of Symbolic References – The binary representation of a class or interface references other classes and interfaces and their fields, methods, and constructors symbolically, using the binary names of the other classes and interfaces. For fields and methods, these symbolic references include the name of the class or interface type that declares the field or method as well as the name of the field or method itself, together with appropriate type information. Before a symbolic reference can be used it must undergo resolution, wherein a symbolic reference is checked to be correct and, typically, replaced with a direct reference that can be more efficiently processed if the reference is used repeatedly.

Initialization of classes and interfaces

Initialization of a class consists of executing its static initializers and the initializers for static fields (class variables) declared in the class. Initialization of an interface consists of executing the initializers for fields (constants) declared there. Before a class is initialized, its superclass must be initialized, but interfaces implemented by the class are not initialized. Similarly, the superinterfaces of an interface are not initialized before the interface is initialized. A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

  • T is a class and an instance of T is created.
  • T is a class and a static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the reference to the field is not a compile-time constant. References to compile-time constants must be resolved at compile time to a copy of the compile-time constant value, so uses of such a field never cause initialization.

Invocation of certain reflective methods in the class Class and in the package java.lang.reflect also cause class or interface initialization. A class or interface will not be initialized under any other circumstance.

Example

One of the reasons to write a class loader is to control the JVM’s class loading behavior. A class is identified using its package name and class name. For classes that implement java.io.Serializable, the serialVersionUID plays a significant role in versioning the class. This stream-unique identifier is a 64-bit hash of the class name, interface class names, methods and fields. If the above aspects match, the classes are of the same version. Reasons for writing a class loader are:

  • To allow class loading from alternative repositories. This is the most common case, in which we might want to load classes from other locations, for example, over a network connection.
  • To partition user code. This case is less frequently used in Java clients, but widely used in servlet engines.
  • To allow the unloading of classes. This case is useful if the application creates large numbers of classes that are used for only a finite period. Because a class loader maintains a cache of the classes that it has loaded, these classes cannot be unloaded until the class loader itself has been dereferenced. For this reason, system and extension classes are never unloaded, but application classes can be unloaded when their classloader is.

The following code shows an example of a class loader:

public class VideotheekClassLoader extends ClassLoader {

    private String root = "/home/oracle/temp";

    public VideotheekClassLoader() {
        super(VideotheekClassLoader.class.getClassLoader());
    }

    @Override
    protected Class<&#63;>; findClass(String name) throws ClassNotFoundException {
        byte[] bytes = findClassBytes(name);
        if (bytes == null) {
            throw new ClassNotFoundException(name);
        } else {
            return defineClass(name, bytes, 0, bytes.length);
        }
    }

    private byte[] findClassBytes(String className) {
        String path = root + File.separatorChar + className.replace('.', File.separatorChar) + ".class";
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(path);
            byte[] bytes = new byte[inputStream.available()];
            inputStream.read(bytes);
            return bytes;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}

If the parent class loader is correctly set, whenever a class is requested out of a ClassLoader instance, it should ask the parent first. If the parent cannot find it (which again means that its parent also cannot find the class, and so on), and if the findBootstrapClass method also fails, the findClass method is invoked.

The default implementation of findClass will throw a ClassNotFoundException. It is expected that this method is implemented when making custom class loaders. The class loader needs to fetch the byte codes from some arbitrary source. The source can be a file system, a network URL, a database or any other source that can generate byte code compliant with the Java byte code specification. Once the byte code is retrieved, the method should call the defineClass method. The runtime environment is very particular about which ClassLoader instance calls this method. If two different ClassLoader instances define byte codes from the same sources, the defined classes are different. The loading of a class can be broken down into three phases:

  1. Loading – The loading phase consists of locating the required class file (by searching through respective classpaths) and loading the bytecode. Within the JVM the loading process gives a basic memory structure to the class object. Methods, fields and other classes referenced are not dealt with at this stage. As a result the class is not useable.
  2. Linking – Can be broken down into three main stages:
    • Bytecode verification – The classloader does a number of checks on the bytecodes of the class to ensure that it is well formed and well behaved.
    • Class preparation – This stage prepares the necessary data structures that represent fields, methods and implemented interfaces that are defined within each class.
    • Resolving – The class loader loads all the other classes referenced by a particular class. The classes can be referenced in a number of ways: superclasses, interfaces, fields method signatures, local variables used in methods.
  3. Initialization – During this phase any static initializers contained within a class are executed. At the end of this phase static fields are initialized to their default values.

At the end of the three phases a class is loaded and is ready for use.

In the Java runtime each and every class will have its code available in the form of a first-class Java object, which is an instance of java.lang.Class. Whenever we compile a Java file, the compiler will embed a public static final field of the type java.lang.Class, in the emitted byte code. Since this field is public static, we can access it using dotted notation, like this java.lang.Class clazz = ClassLoaders.class;. Once a class is loaded in the JVM, the same class will not be loaded again. Which means that a class loaded into a JVM has a specific identity. In Java, a class is identified by its fully qualified class name. The fully qualified class name consists of the package name and the class name. A class in a JVM is identified by using its fully qualified class name along with the instance of the ClassLoader that loaded the class.

In a JVM, a class is loaded by an instance of a java.lang.ClassLoader. Whenever a new JVM is started by typing java MyStartClass, the bootstrap class loader is responsible for loading key Java classes. The runtime classes are packaged inside of the jre/lib/rt.jar. The bootstrap class loader is a native implementation so the behavior can differ accross JVMs. In relation to this, we will get null if we try to get the class loader of a core Java runtime class, such as String.class.getClassLoader();. We can store extension libraries in the path given by the System property java.ext.dirs. The sun.misc.Launcher$ExtClassLoader is responsible for loading all JAR files kept in the extensions directory. The third and most important class loader from a developer perspective is the sun.misc.Launcher$AppClassLoader. The application class loader is responsible for loading all of the classes kept in the path corresponding to the System property java.class.path.

The java.lang.Thread class, contains the method getContextClassLoader(), which returns the context class loader for a particular thread. The context class loader is provided by the creator of the thread for use by code running in this thread when loading classes and resources. If it is not set, the default is the class loader context of the parent thread. The context class loader of the primordial thread is typically set to the class loader used to load the application.

Let us take a look at an example which uses different kinds of class loading aspects

package classloaders;

import java.lang.management.ManagementFactory;

import java.lang.management.MemoryPoolMXBean;

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

import java.util.Iterator;

public class Test {
    public Test() {
    }

    public static void main(String[] args) {
        testClassLoadingStuff();
		printClassLoaderInfo();
        memoryUsageInformation();
		testClassNotFound();
        testNoClassDefFound();
        testClassCast();
    }

    public static void testClassLoadingStuff() {
        VideotheekClassLoader loader1 = new VideotheekClassLoader();
        VideotheekClassLoader loader2 = new VideotheekClassLoader();

        Class clazz1 = null;
        Class clazz2 = null;
        Class clazz3 = null;
        try {
            clazz1 = loader1.loadClass("classloaders.Test");
            System.out.println(clazz1.getName() + "@" + clazz1.hashCode() + " loaded by " + clazz1.getClassLoader());

            clazz2 = loader1.loadClass("classloaders.Test");
            System.out.println(clazz2.getName() + "@" + clazz2.hashCode() + " loaded by " + clazz2.getClassLoader());

            System.out.println(clazz1.equals(clazz2));
            // Gives true: fully qualified class name is equal and also loaded by the same class loader instance

            clazz3 = loader2.loadClass("classloaders.Test");
            System.out.println(clazz3.getName() + "@" + clazz3.hashCode() + " loaded by " + clazz3.getClassLoader());

            System.out.println(clazz1.equals(clazz3));
            // Gives false: fully qualified class name is equal but the clazz3 instance is loaded by a different class loader instance
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private static void printClassLoaderInfo() {
        System.out.println("CLASSLOADER OF THIS CLASS " + Test.class.getClassLoader());
        System.out.println("CONTEXT CLASSLOADER " + Thread.currentThread().getContextClassLoader());
        System.out.println("BOOTSTRAP CLASSES " + System.getProperty("sun.boot.class.path"));
        System.out.println("EXTENSION CLASSES DIRECTORY " + System.getProperty("java.ext.dirs"));
        System.out.println("USER CLASS PATH " + System.getProperty("java.class.path"));
        System.out.println("JAVA HOME " + System.getProperty("java.home"));
    }

    private static void memoryUsageInformation() {
        System.out.println(ManagementFactory.getMemoryMXBean().getHeapMemoryUsage());
        System.out.println(ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage());

        Iterator<MemoryPoolMXBean> iterator = ManagementFactory.getMemoryPoolMXBeans().iterator();
        while (iterator.hasNext()) {
            MemoryPoolMXBean memoryPoolMXBean = iterator.next();
            System.out.println(memoryPoolMXBean.getName());
            System.out.println(memoryPoolMXBean.getType());
            System.out.println(memoryPoolMXBean.getUsage());
            System.out.println(memoryPoolMXBean.getPeakUsage());
            System.out.println(memoryPoolMXBean.getCollectionUsage());
        }
    }

    private static void testClassNotFound() {
        URLClassLoader loader = null;
        try {
            loader = new URLClassLoader(new URL[]{new URL("file:///c:/temp")});
            loader.loadClass("some.where.SomeClass");
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private static void testNoClassDefFound() {
        // create a new class
        // reference this class
        // compile the code
        // remove the class
    }

    private static void testClassCast() {
        try {
            doSomethingWithSomething("blabla");
        } catch (ClassCastException e) {
            e.printStackTrace();
        }
    }

    private static void doSomethingWithSomething(Object something) {
        Double result = (Double) something;
        System.out.println(result);
    }
}

There are two ways a class can be loaded – explicitly or implicitly. Explicit class loading occurs when a class is loaded using:

  • classLoader.loadClass();
  • Class.forName();

When one of these methods is invoked, the class whose name is specified as an argument is loaded by the class loader. If the class is already loaded, then a reference is returned; otherwise the loader goes through the delegation model to load the class. Implicit class loading occurs when a class is loaded as a result of a reference, instantiation, or inheritance. In each of these cases, the loading is initiated under the covers and the JVM resolves the necessary references and loads the class.

Class loader constraints ensure consistency of the class space in the JVM. In other words, when two class loaders load different classes (i.e., different bytecodes) with the same name, class loader constraints guarantee that there will be no type mismatch between them. A class loader constraint is violated when the following four conditions hold:

  • There exists a loader L such that L has been recorded by the JVM as an initiated loader of a class C named N.
  • There exists a loader L' such that L' has been recorded by the JVM as an initiated loader of a class C' named N.
  • The equivalence relation defined by the (transitive closure of the) set of imposed constraints implies N L = N L'.
  • C != C'.

While the simplest way to avoid class loader violations is to have only one copy of a class in the system, it is sometimes necessary to have multiple versions. One possible way to avoid constraint violations, while still deploying multiple versions of a class, is to use a peer class loading model. Peer class loading does not follow the traditional hierarchical delegation structure for class loaders. Instead, it has a set of class loaders that are unrelated except that they have the same parent (usually the system class loader). These class loaders can delegate not only to their parent, but also to their peers. This kind of class loader structure allows discrete class spaces to exist within one JVM; thus, it is very useful for running componentized products.

The ClassNotFoundException is the most common type of class loading exception. It occurs during the loading phase. Thrown when an application tries to load a class through its string name using:

  • The forName method in Class.
  • The findSystemClass method in ClassLoader.
  • The loadClass method in ClassLoader.

but no defition for the class with the specified name could be found. By throwing a ClassNotFoundException, the class loader informs us that the bytecode required to define the class is not present in the locations where the class loader is looking for it. There may be classes in a system that cannot be seen by a class loader. This is because a class loader only sees classes that are loaded by itself or loaded by class loaders to which it has a reference. In the class loading delegation model, the classes that are visible to a class loader are those that are loaded by itself or loaded by its parent – in other words, a class loader cannot look down.

NoClassDefFoundError is thrown if the JVM or a ClassLoader instance tries to load the definition of a class and no definition of the class could be found. The searched for class definition existed when the currently executing class was compiled but the definition can no longer be found. Essentially this means that a NoClassDefFoundError is thrown as a result of a unsuccessful implicit class load.

A ClassCastException is thrown as a result of incompatible types found in a type comparison. Thrown to indicate that the code has attempted to cast an object to a subclass of which it is not an instance. Given an object being tested and a target class being cast to, the class loader checks the following rules:

  • For a normal object (non-array); the object must be an instance of the target class or a subclass of that target class. If the target is an interface, then it is considered a subclass if it implements that interface.
  • For an array type; the target class must be an array type or java.lang.Object, java.lang.Cloneable or java.io.Serializable.

If either of the above rules are violated, then a ClassCastException is thrown by the class loader. It may be sensible to use the instanceof check prior to doing the cast, or in the case of arrays use generics.

Now that we have a basic understanding of how class loading works, let us see how to package enterprise applications such that the classes used by the application can be found in an appropriate manner.

Packing applications

We have a number of ways to package and deploy an application consisting of EJB and Web modules:

  • Standalone modules – Deploy the EJB archives and Web archives directly to the server as standalone applications. The Web components can access the EJB components using remote business interfaces.
  • Enterprise archive – Package the EJB and Web modules into an enterprise archive (.ear) file, which is deployed as a single unit to the server.
  • Exploded enterprise directory – Package the EJB and Web modules into an enterprise directory structure, which is deployed as a single unit to the server. Support for this unarchived deployment format is a WebLogic extension to Java EE.

With the first option each EJB archive and Web archive is deployed as an independent Java EE application, which is not recommended, i.e., each application is loaded with an independent classloader. Because each classloader is independent, classes loaded by one classloader are not visible to classes loaded by other classloaders. For a Web application to invoke EJBs, it must include the client-related EJB classes. Because the classes are loaded by unrelated classloaders, communication between the modules must use remote interfaces and RMI serialization. The overhead of this serialization is acceptably small when making a remote network call, but is costly for more frequent, local communication between application modules.

All classloaders used for the separate applications are children of the Java system classloader. The classes in the system classloader (configured by the CLASSPATH environment variable) are used for the server process itself during startup. Components in a child classloader may refer to classes present in parent classloaders, meaning that the EJB and Web application can use classes loaded by the system classloader. An alternative to placing jar files for each EJB archive in each Web archive is to put such files in the system classpath. There are two reasons to avoid using the system classloader for application classes:

  • When application classes are placed in the system classpath we can not redeploy the application completely, because classes loaded by the system classloader cannot be removed and reloaded. If we need to change classes loaded by the system classloader, we have to restart the whole server for the changes to be picked up.
  • Classes in the parent classloader cannot refer directly to classes in child classloaders. If any class in the system classloader attempts to use a class found only in the EJB archive or Web archive, we get a ClassNotFoundException or a NoClassDefFoundError. If this problem is addressed by moving more and more classes to the system classpath, soon we have the situation in which every class in the application winds up in the system classloader and all hope for hot redeployment is gone.

It is recommended that only classes required for system-wide components be present in the system classpath and therefore loaded by the Java system classloader, for example, JDBC driver classes. Even classes such as frameworks used by the application do not belong in the system classpath.

WebLogic uses a separate classloader to load classes from the domain lib directory. This classloader is a child of the system classloader, and a parent of the application classloader. The classes and resources in any jar file placed in this directory are automatically available to all applications. However, the domain lib classloader does not support redeployment or dynamic reloading, and cannot refer directly to code in the application classloader. The domain lib directory should be considered the equivalent to the system classpath, and not be used for application classes.

The other two deployment options involve creating an enterprise archive containing the EJB and Web archives. The only difference between the two is the final packaging step: should the enterprise application be deployed as an exploded directory or as a single enterprise archive (.ear) file?

The standard directory structure and contents of an enterprise application are shown below:

Application.ear
	APP-INF/lib
	META-INF
		application.xml
		weblogic-application.xml
		weblogic-diagnostics.xml
		MANIFEST.MF
	EJB.jar
		META-INF
			ejb-jar.xml
			weblogic-ejb-jar.xml
			persistence.xml
			MANIFEST>MF
		packages containing Java classes
	Web.war
		META-INF
			MANIFEST.MF
		WEB-INF
			classes (packages containing Java classes)
			lib
			web.xml
			weblogic.xml

The Application.ear directory contains all of the individual application components. The server treats everything in the Application.ear directory as a single Java EE application, eliminating many of the problems associated with standalone modules. The EJB and Web archives are placed at the root level of the enterprise application directory structure along with a META-INF directory containing optional descriptors and any other directories required by the application.

An important difference with deploying the modules standalone is the structure of the classloaders used to load application classes. When EJB and Web modules are placed in an enterprise application structure, WebLogic uses a classloader structure, in which all EJB modules are loaded by a single top-level application classloader and the Web module classloader is a child of the application classloader. Recall that a child classloader is able to refer to all classes loaded by its parent classloader, so the Web module has full access to the classes in the EJB module, i.e,

  • Web modules may use local EJB interfaces and make Java method calls to EJB components located in the same enterprise application. There is no need to use remote interfaces or Serializable parameters and return types, and
  • There is no need for the Web modules to include client EJB classes, because they have full visibility to these classes by virtue of the parent application classloader.

Bundled libraries

Bundled libraries (jar files containing code) contain components of the application, for example, a third-party product library code, such as, Hibernate or Spring. Any code that an application relies on can be packaged in a bundled library. Bundled libraries provide three advantages over packaging classes on the system classpath:

  • An application that uses bundled libraries has fewer dependencies on server configurations, which makes the application easier to deploy.
  • Bundled libraries are loaded by the application’s classloader, with the result that bundled libraries changes are made effective by redeploying the application, without needing to restart the server.
  • Applications that rely on different versions of the bundled library can have their own copies and be deployed to the same server.

The drawbacks of bundled libraries over packaging classes on the system classpath are that they increase the size of the application, and that if many applications include the same bundled library their combined memory footprint is larger. Bundled libraries can be included in an application as follows:

  • Manifest Class-Path header – A module in the application can include a Class-Path header in its META-INF/MANIFEST.MF file that refers to a list of jar files. These jar files will be loaded as bundled libraries, and can be placed anywhere in the application directory structure. Each Class-Path list entry is treated as a path relative to the referring module. Any Class-Path manifest headers in the jar files will be used recursively to load other bundled libraries and so on.
  • Web archive WEB-INF/lib – Web archives provide a built-in mechanism to load classes in the same classloader as the Web module itself: the WEB-INF/lib directory. Any jar file placed in that directory will be loaded automatically by the Web module classloader, and the loaded classes will be available to the Web components within the module. These jar files can have manifest Class-Path headers that reference other bundled libraries. There is also a WEB-INF/classes directory for unarchived class files. Classes loaded from WEB-INF/classes, WEB-INF/lib, or bundled libraries referred by libraries in WEB-INF/lib, are loaded in the Web module classloader, and are not visible to other modules within the application.
  • WebLogic APP-INF/lib – WebLogic allows jar files to be included as bundled libraries in the APP-INF/lib directory. These jar files can have manifest Class-Path headers that refer to other bundled libraries. WebLogic also supports an APP-INF/classes directory for unarchived class files. These APP-INF directories provide the same type of behavior as the WEB-INF directories do for Web modules, but load classes into the application classloader.
  • Java EE 5 application library directory – Java EE 5 introduced a similar feature to the WebLogic APP-INF/lib directory. Any jar file in a Java EE application’s library directory will be treated as a bundled library and loaded in the application classloader. These jar files can have manifest Class-Path headers that refer to other bundled libraries. The default library directory is called lib, but can be changed using the library-directory element of the application.xml descriptor. An empty library-directory element means there is no library directory.

Let us consider an example of packaging bundled libraries. According to module conventions EJB and Web modules will automatically be loaded. On the other hand, somelibrary.jar placed in the directory libraries will not automatically be loaded and must be specifically handled. Options for doing this are defining a Java EE library directory or adding a manifest Class-Path entry.

The library directory option requires adding an application.xml descriptor to a META-INF directory and using the library-directory element to set the Java EE library directory to libraries, for example,

<application ...>
    <module>
        <ejb>EJB.jar</ejb>
    </module>
    <module>
        <web>
            <web-uri>Web.war</web-uri>
            <context-root>MiddlewareMagic</context-root>
        </web>
    </module>
	<library-directory>libraries</library-directory>
</application>

The manifest Class-Path entry option requires adding a META-INF/MANIFEST.MF file with the following contents:

Manifest-Version: 1.0
Class-Path: libraries/somelibrary.jar

Note that lines in manifest files are limited to 72 characters. Long Class-Path headers may be continued onto subsequent lines by starting each line with a single space.

Note that the manifest Class-Path header is the only packaging method that allows control over the precedence of classes in bundled libraries. Order is not defined for the other methods. Subtle problems can arise from assuming that order is defined, for example, when a file system changes this can also change the loading order of WEB-INF/lib libraries, causing an application to malfunction. With the Class-Path header, the bundled libraries that appear earlier in the Class-Path header have a higher priority. This can be useful if two bundled libraries contain the same classes and we need to ensure that one is given priority.

Sharing libraries

WebLogic provides two ways to package and manage libraries to be shared between applications: optional packages and shared libraries. Optional packages are part of the Java EE 5 specification. An optional package is a plain jar file containing compiled classes that can be deployed to a server. Applications and other optional packages can refer to the optional packages they depend on in their manifest files – this reference will be resolved at deployment time. Optional packages can also have a version, and different versions of the same optional package can be deployed to the server. The manifest file of the referring application will determine which version of the library it will use.

At runtime, optional packages are loaded in the application classloader, and so behave in a similar fashion to bundled libraries packaged in the application. If two applications deployed to a server use the same optional package, there will be two separate copies of the classes loaded in the server. Optional packages are not a way to reduce the memory footprint of an application.

Shared libraries are specific to WebLogic. Like optional packages, shared libraries can be deployed to a server; optionally can have a version; and can be referred to by applications or by other shared libraries. The main difference from optional packages is that shared libraries can also be enterprise applications, EJB modules, or Web modules, as well as plain .jar files containing classes and resources. The shared library name refers to this ability to contain Java EE applications and modules, but it is important to remember that this is a WebLogic specific feature.

When an application that refers to a shared library is deployed, it behaves as if the files in the shared library were merged with its own. Like optional packages, shared libraries provide a way to share code between applications, but each referring application is deployed with its own runtime copies of the classes. The following shows an example (weblogic.xml) of how to configure an application to use a shared library:

<weblogic-web-app ...>
	<library-ref>
		<library-name>coherence-web-spi</library-name>
		<specification-version>1.0.0.0</specification-version>
		<implementation-version>1.0.0.0</implementation-version>
		<exact-match>true</exact-match>
	</library-ref>
</weblogic-web-app>

Optional packages and shared libraries have much the same runtime characteristics as bundled libraries. The benefit of optional packages and shared libraries is that they allow libraries to be managed independently from applications, making the application archives smaller and faster to deploy. On the other hand, an application that relies on optional packages or shared libraries is less self-contained. Optional packages and shared libraries come into their own when used to provide functionality for one or more applications, where we wish to be able to upgrade that functionality without having to change the applications.

Manipulating class loading

Filtering classloaders allow a specific customization of the class loading behavior. Filtering classloaders are used to resolve clashes between classes that are present in the application and the system classpath, or in the domain lib directory. By default, if a class is present on both the system classpath and the application, the system classpath copy is used. Filtering classloaders are commonly used to package a different version of a third-party library in the application. Filtering classloaders are controlled by using the prefer-application-packages element in weblogic-application.xml. Suppose we want to use an antlr version provided by Hibernate instead of the one packaged with WebLogic. We could package antlr as a bundled library in the application, and use the following descriptor entry:

<prefer-application-packages>
	<package-name>antlr.*</package-name>
</prefer-application-packages>

The package-name expression can have an optional wildcard * for its last character, which matches any characters.

As an example note the following exceptions

org.hibernate.HibernateException: Errors in named queries: Film.findAll, Persoon.findPersoonBySofinummer, Film.findFilmsForPersoon, Persoon.findAll
	at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:365)
	at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1300)
	at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:691)
	at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:127)
org.springframework.context.ApplicationContextException: Can't load stylesheet from 'classpath:xsl/personalMenu.xsl'; nested exception is javax.xml.transform.TransformerConfigurationException: Could not compile stylesheet
        at org.springframework.web.servlet.view.xslt.XsltView.loadTemplates(XsltView.java:424)
        at org.springframework.web.servlet.view.xslt.XsltView.initApplicationContext(XsltView.java:183)
        at org.springframework.context.support.ApplicationObjectSupport.initApplicationContext(ApplicationObjectSupport.java:119)
        at org.springframework.web.context.support.WebApplicationObjectSupport.initApplicationContext(WebApplicationObjectSupport.java:69)
        at org.springframework.context.support.ApplicationObjectSupport.setApplicationContext(ApplicationObjectSupport.java:73)
Caused By: javax.xml.transform.TransformerConfigurationException: Could not compile stylesheet
        at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTemplates(TransformerFactoryImpl.java:885)
        at weblogic.xml.jaxp.WebLogicTransformerFactory.newTemplates(WebLogicTransformerFactory.java:197)
        at weblogic.xml.jaxp.RegistryTransformerFactory.newTemplates(RegistryTransformerFactory.java:173)
        at org.springframework.web.servlet.view.xslt.XsltView.loadTemplates(XsltView.java:417)
        at org.springframework.web.servlet.view.xslt.XsltView.initApplicationContext(XsltView.java:183)

Both are not really indicating a problem due to class loading. The first says there is an error in a named query, so a logical reaction here would be to check out the named query and try to correct. After quite a large timespan (in some cases), we come to the conclusion that there is nothing wrong with the query. The same goes for the second exception, which indicates a stylesheet cannot be compiled, so there must be something wrong with it, or not? Unfortunetaly, problems due to class loading are hard to relate to the real problem, i.e., class loading. We we finally come to the conclusion that it is problem related to the order in which class are loaded, we have to know which classes are clashing.

In the cases presented above the clashes are respectively due to antlr and xalan. WebLogic loads versions of both, but for the application these versions are not the right ones. So how can we resolve these class loading issues?

When WebLogic is set-up in development mode, we can use the classloader analysis tool, when not we have to use our own brains. In order to resolve the above exception, we can use the following (in for example the weblogic.xml file)

<weblogic-web-app ...>
	<show-archived-real-path-enabled>true</show-archived-real-path-enabled>
	<container-descriptor>
		<prefer-application-packages>
			<package-name>antlr.*</package-name>
			<package-name>org.apache.xalan.*</package-name>
		</prefer-application-packages>
	</container-descriptor>
	<context-root>someapplication</context-root>
</weblogic-web-app>

Note another setting in the weblogic.xml configuration above. The show-archived-real-path-enabled element specifies the behavior of getRealPath for archived Web applications. When set to true, getRealPath returns the canonical path of the resource files. If the show-archived-real-path-enabled element is set to false, the servlet container will return the real path of files in archived Web applications as null. Not really related to class loading, but when working with velocity a very important parameter to set.

To run Apache CXF on WebLogic, we need to following two system parameters: -Djavax.xml.soap.MessageFactory=weblogic.xml.saaj.MessageFactoryImpl -Djavax.xml.soap.SOAPConnectionFactory=weblogic.wsee.saaj.SOAPConnectionFactoryImpl. Also note we can, and may need to, specify other options in the weblogic-application.xml file such as XML processing factories, for example,

<weblogic-application ...>
    <xml>
		<parser-factory>
			<saxparser-factory>org.apache.xerces.jaxp.SAXParserFactoryImpl</saxparser-factory>
			<document-builder-factory>org.apache.xerces.jaxp.DocumentBuilderFactoryImpl</document-builder-factory>
			<transformer-factory>org.apache.xalan.processor.TransformerFactoryImpl</transformer-factory>
		</parser-factory>
	</xml>
	<application-param>
		<param-name>webapp.encoding.default</param-name>
		<param-value>UTF-8</param-value>
	</application-param>
	<prefer-application-packages>
		<package-name>javax.jws.*</package-name>
		<package-name>org.apache.xerces.*</package-name>
		<package-name>org.apache.xalan.*</package-name>
	</prefer-application-packages>
</weblogic-application>

More information concerning the xml element can be found here.

References

[1] Understanding WebLogic Server Application Classloading.
[2] The Basics of Java Class Loaders.
[3] Making the Most of WebLogic Class Loaders.
[4] Internals of Java Class Loading.
[5] Class ClassLoader.