Class loading and Class Loaders

Introduction

Class loading, within the plethora of environments that Ehcache can be running, is a somewhat vexed issue. Since ehcache-1.2, all classloading is done in a standard way in one utility class: ClassLoaderUtil.

Plugin class loading

Ehcache allows plugins for events and distribution. These are loaded and created as follows:

         /**
 * Creates a new class instance. Logs errors along the way. Classes are loaded
 * using the Ehcache standard classloader.
 *
 * @param className a fully qualified class name
 * @return null if the instance cannot be loaded
 */
public static Object createNewInstance(String className) throws CacheException {

    Class clazz;
    Object newInstance;
    try {
	clazz = Class.forName(className, true, getStandardClassLoader());
    } catch (ClassNotFoundException e) {
		//try fallback
		try {
		    clazz = Class.forName(className, true, getFallbackClassLoader());
		} catch (ClassNotFoundException ex) {
		    throw new CacheException("Unable to load class " + className +
					     ". Initial cause was " + e.getMessage(), e);
		}
    }
    try {
	newInstance = clazz.newInstance();
    } catch (IllegalAccessException e) {
	throw new CacheException("Unable to load class " + className +
				 ". Initial cause was " + e.getMessage(), e);
    } catch (InstantiationException e) {
	throw new CacheException("Unable to load class " + className +
				 ". Initial cause was " + e.getMessage(), e);
    }
    return newInstance;
}


/**
 * Gets the <code>ClassLoader</code> that all classes in ehcache, and extensions,
 *  should use for classloading. All ClassLoading in Ehcache should use this one.
 * This is the only thing that seems to work for all of the class loading
 * situations found in the wild.
 * @return the thread context class loader.
 */
public static ClassLoader getStandardClassLoader() {
    return Thread.currentThread().getContextClassLoader();
}

/**
 * Gets a fallback <code>ClassLoader</code> that all classes in ehcache, and
 * extensions, should use for classloading. This is used if the context class loader
 * does not work.
 * @return the <code>ClassLoaderUtil.class.getClassLoader();</code>
 */
public static ClassLoader getFallbackClassLoader() {
    return ClassLoaderUtil.class.getClassLoader();
}

      

If this does not work for some reason a CacheException is thrown with a detailed error message.

Loading of ehcache.xml resources

If the configuration is otherwise unspecified, Ehcache looks for a configuration in the following order:

  • Thread.currentThread().getContextClassLoader().getResource(“/ehcache.xml”)
  • ConfigurationFactory.class.getResource(“/ehcache.xml”)
  • ConfigurationFactory.class.getResource(“/ehcache-failsafe.xml”)

Ehcache uses the first configuration found. Note the use of “/ehcache.xml” which requires that ehcache.xml be placed at the root of the classpath, i.e. not in any package.

Classloading with Terracotta clustering

If Terracotta clustering is being used with valueMode=”serialization” then keys and values will be moved across the cluster in byte[] and deserialized on other nodes.

The classloaders used (in order) to instantiate those classes will be:

  • Thread.currentThread().getContextClassLoader()
  • The classloader that defined the CacheManager initially