From 23df003ef1f01cfb8ba4295c04c5dba9073c7f20 Mon Sep 17 00:00:00 2001 From: Robert Burrell Donkin Date: Wed, 9 Mar 2005 21:13:21 +0000 Subject: [PATCH] Improved javadocs for WeakHashTable. More readable explaination contributed by Simon Kitching. git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/logging/trunk@156689 13f79535-47bb-0310-9956-ffa450edef68 --- .../commons/logging/impl/WeakHashtable.java | 107 +++++++++++++----- 1 file changed, 79 insertions(+), 28 deletions(-) diff --git a/optional/src/java/org/apache/commons/logging/impl/WeakHashtable.java b/optional/src/java/org/apache/commons/logging/impl/WeakHashtable.java index bdcf4d1..232b365 100644 --- a/optional/src/java/org/apache/commons/logging/impl/WeakHashtable.java +++ b/optional/src/java/org/apache/commons/logging/impl/WeakHashtable.java @@ -23,10 +23,14 @@ import java.util.*; /** *

Implementation of Hashtable that uses WeakReference's - * to hold it's keys thus allowing them to be reclaimed by the garbage collector. - * This class follows the symantics of Hashtable as closely as possible. - * It therefore does not accept null values or keys. - *

+ * to hold its keys thus allowing them to be reclaimed by the garbage collector. + * The associated values are retained using strong references.

+ * + *

This class follows the symantics of Hashtable as closely as + * possible. It therefore does not accept null values or keys.

+ * + *

Note: + * This is not intended to be a general purpose hash table replacement. * This implementation is also tuned towards a particular purpose: for use as a replacement * for Hashtable in LogFactory. This application requires * good liveliness for get and put. Various tradeoffs @@ -34,36 +38,83 @@ import java.util.*; *

*

* Usage: typical use case is as a drop-in replacement - * for the Hashtable use in LogFactory for J2EE enviroments + * for the Hashtable used in LogFactory for J2EE enviroments * running 1.3+ JVMs. Use of this class in most cases (see below) will * allow classloaders to be collected by the garbage collector without the need * to call {@link org.apache.commons.logging.LogFactory#release(ClassLoader) LogFactory.release(ClassLoader)}. *

+ * + *

org.apache.commons.logging.LogFactory looks to see whether this + * class is present in the classpath, and if so then uses it to store + * references to the LogFactory implementationd it loads + * (rather than using a standard Hashtable instance). + * Having this class used instead of Hashtable solves + * certain issues related to dynamic reloading of applications in J2EE-style + * environments. However this class requires java 1.3 or later (due to its use + * of java.lang.ref.WeakReference and associates) and therefore cannot be + * included in the main logging distribution which supports JVMs prior to 1.3. + * And by the way, this extends Hashtable rather than HashMap + * for backwards compatibility reasons. See the documentation + * for method LogFactory.createFactoryStore for more details.

+ * + *

The reason all this is necessary is due to a issue which + * arises during hot deploy in a J2EE-like containers. + * Each component running in the container owns one or more classloaders; when + * the component loads a LogFactory instance via the component classloader + * a reference to it gets stored in the static LogFactory.factories member, + * keyed by the component's classloader so different components don't + * stomp on each other. When the component is later unloaded, the container + * sets the component's classloader to null with the intent that all the + * component's classes get garbage-collected. However there's still a + * reference to the component's classloader from the "global" LogFactory's + * factories member! If LogFactory.release() is called whenever component + * is unloaded (as happens in some famous containers), the classloaders will be correctly + * garbage collected. + * However, holding the classloader references weakly ensures that the classloader + * will be garbage collected without programmatic intervention. + * Unfortunately, weak references are + * only available in java 1.3+, so this code only uses WeakHashtable if the + * class has explicitly been made available on the classpath.

+ * *

- * In a particular usage scenario, use of WeakHashtable alone will - * be insufficent to allow garbage collection of a classloader without a call to - * release. If the abstract class LogFactory is - * loaded by a parent classloader and a concrete subclass implementation of - * LogFactory is loaded by a child classloader, the concrete - * implementation will have a strong reference to the child classloader via the - * chain getClass().getClassLoader(). The WeakHashtable - * will have a strong reference to the LogFactory implementation as - * one of the values in its map. This chain of references will prevent - * collection of the child classloader. - *

+ * Because the presence of this class in the classpath ensures proper + * unload of components without the need to call method + * {@link org.apache.commons.logging.LogFactory#release(ClassLoader) LogFactory.release ClassLoader)}, + * it is recommended that this class be deployed along with the standard + * commons-logging.jar file when using commons-logging in J2EE + * environments (which will presumably be running on Java 1.3 or later). + * There are no know ill effects from using this class.

+ * *

- * Such a situation would typically only occur if commons-logging.jar were - * loaded by a parent classloader (e.g. a server level classloader in a - * servlet container) and a custom LogFactory implementation were - * loaded by a child classloader (e.g. a web app classloader). If use of - * a custom LogFactory subclass is desired, ensuring that the - * custom subclass is loaded by the same classloader as LogFactory - * will prevent problems. In normal deployments, the standard implementations - * of LogFactory found in package org.apache.commons.logging.impl - * will be loaded by the same classloader that loads LogFactory - * itself, so use of the standard LogFactory implementations - * should not pose problems. + * Limitations: + * There is still one (unusual) scenario in which a component will not + * be correctly unloaded without an explicit release. Though weak references + * are used for its keys, it is necessary to use + * strong references for its values.

* + *

If the abstract class LogFactory is + * loaded by the container classloader but a subclass of + * LogFactory [LogFactory1] is loaded by the component's + * classloader and an instance stored in the static map associated with the + * base LogFactory class, then there is a strong reference from the LogFactory + * class to the LogFactory1 instance (as normal) and a strong reference from + * the LogFactory1 instance to the component classloader via + * getClass().getClassLoader(). This chain of references will prevent + * collection of the child classloader.

+ * + *

+ * Such a situation occurs when the commons-logging.jar is + * loaded by a parent classloader (e.g. a server level classloader in a + * servlet container) and a custom LogFactory implementation is + * loaded by a child classloader (e.g. a web app classloader).

+ * + *

To avoid this scenario, ensure + * that any custom LogFactory subclass is loaded by the same classloader as + * the base LogFactory. Creating custom LogFactory subclasses is, + * however, rare. The standard LogFactoryImpl class should be sufficient + * for most or all users.

+ * + * * @author Brian Stansberry */ public final class WeakHashtable extends Hashtable { @@ -434,4 +485,4 @@ public final class WeakHashtable extends Hashtable { return referenced; } } -} \ No newline at end of file +}