这个问题复杂情况可见这个帖子:
http://www.jdon.com/jive/thread.jsp?forum=16&thread=10291

当然这是JBoss的特殊ClassLoader策略,Weblogic还不一样。

raimundo说的没错。我补充一点,就是Class.forName(String className)是用调用了Class.forName(String className)这个方法的类的ClassLoader来加载className类的。因为确省情况下程序中的类都是由System ClassLoader来加载的,所以ClassLoader.forName()也用System ClassLoader来加载类。每个线程对象在创建的时候都确省用System ClassLoader作为context ClassLoader,所以Thread.getContextClassLoader()通常也返回System ClassLoader,除非手动设置Thread.setContextClassLoader()。
关于banq前面举的例子,raimundo已经解释得很清楚了。我用我做过的一个软件来说明我如何使用ClassLoader的吧。我的软件支持“插件”,每个“插件”都可能包含jar文件,所以为了避免类同名的情况等原因,程序会给每个“插件”创建一个ClassLoader,所有这个“插件”用到的类都由“插件”自己的ClassLoader来加载。其实我觉得用ClassLoader难就难在scope上,如我前面的例子,“插件”除了可以加载自己jar文件里的类外,是否还可以加载公共目录下的类;如果“插件”的某个jar文件里的类名与公共目录下的某个类名相同时,应该加载哪一个等等...这些问题并不是技术问题,而是在做ClassLoader设计时就应该考虑好的规则,这些才是做ClassLoader的重点。

>用ClassLoader难就难在scope
这也是我的观点,注意我的标题是"ClassLoader类装载策略",我不是探究ClassLoader类装载原理,程序员杂志上有一篇文章也从字节码来分析classloader,意思说,扒开里面看很简单阿。

其实极限考验是在应用上,也如你说:
“ClassLoader设计时就应该考虑好的规则,这些才是做ClassLoader的重点”

如果整个系统从J2SE处都是你设计的,那么你可以考虑好整个规则,但是如果你在别人的classLoader框架上再做classloader,那么你必须了解别人的classloader规则,而且还要考虑移植性。这就是极限考验了。

SOrry for my broken english, but typing english is mush faster for me.

According to javadoc,
Class.forName(String) is " equivalent to:
Class.forName(className, true, currentLoader)
where currentLoader denotes the defining class loader of the current class. " And obviously sometimes it is not equivalent to the context class loader of the current thread.

According to following URL: http://java.sun.com/developer/technicalArticles/Networking/classloaders/
"A thread's context class loader is, by default, set to the context class loader of the thread's parent. The hierarchy of threads is rooted at the primordial thread (the one that runs the program). The context class loader of the primordial thread is set to the class loader that loaded the application. The thread's context class loader will be the application's class loader. This loader is used by the Java runtime in the Java Remote Method Invocation (RMI) to load classes on behalf of the user application."

My feeling is that a lot of designs make use of this charactor of "context class loader" to pass a special classloader to all of the child processes. But "context class loader" is not designed for this, it primarily enables a class loaded from network to be able to load classes using the application's classloader instead of the network classloader which may not be a child of the applications's class loader.

So we should avoid using context class loader.

SOrry for my broken english, but typing english is mush faster for me.

According to javadoc,
Class.forName(String) is " equivalent to:
Class.forName(className, true, currentLoader)
where currentLoader denotes the defining class loader of the current class. " And obviously sometimes it is not equivalent to the context class loader of the current thread.

According to following URL: http://java.sun.com/developer/technicalArticles/Networking/classloaders/
"A thread's context class loader is, by default, set to the context class loader of the thread's parent. The hierarchy of threads is rooted at the primordial thread (the one that runs the program). The context class loader of the primordial thread is set to the class loader that loaded the application. The thread's context class loader will be the application's class loader. This loader is used by the Java runtime in the Java Remote Method Invocation (RMI) to load classes on behalf of the user application."

My feeling is that a lot of designs make use of this charactor of "context class loader" to pass a special classloader to all of the child processes. But "context class loader" is not designed for this, it primarily enables a class loaded from network to be able to load classes using the application's classloader instead of the network classloader which may not be a child of the applications's class loader.

So we should avoid using context class loader.

这个帖子提出了调用Class.forName出现ClassLoders not Found的问题。
这也属于复杂环境下ClassLoader类装载策略问题,ClassLoader应用策略和Java中文问题一样,解决不好,到处麻烦,解决妥当,一切顺利。
http://www.jdon.com/jive/thread.jsp?forum=16&thread=18096

看了这么长,也不知道究竟出了什么问题。我想jmx实现也是一个基于classloader的典型应用,比如规范要求可以从远程动态加载类等实现。
我想一个实际的应用是在自己实现更新的class的web容器中的自动检测加载,比如象9ias这样的不能自己加载更新的类的应用服务器上。去年年初在用9ias开发的时候,曾有这么一个想法,也动手去做了,但一些技术原因没有完成(现在都忘记是什么技术问题了)。不知道这个想法可行否?也好解决在9ias做开发,机器又慢的人的痛苦?

Thread Context Class Loader
It's also possible to try to resolve class loading problems by using the Java Thread API to obtain a class loader
programmatically. Section 6.2.4.8 of the J2EE 1.3 specification requires all J2EE containers to support the use
of the getContextClassLoader() method on java.util.Thread.
The J2EE specification isn't entirely clear regarding context class loading. However, the intent appears to be
to allow portable classes, such as value objects, to load application classes in whatever container (such as
EJB or web container) they may run in. In practice, the context class loader appears to be in the context of the
current container. To clarify this behavior, let's consider the effect of the following two calls, made by a helper
class that is loaded by the EJB class loader but used in both EJBs and classes running in the web container:
o Class.forName (classname): Will use the class loader of the helper class: in this case, the EJB class
loader. This means that, if the EJB class loader is the parent of the WAR class loader, the helper will
never be able to load classes in the WAR by name.
o Class.forName(classname, true, Thread.currentThread().getContextClassLoader()):
Wi l l use the current container's class loader. This means that the helper will behave differently
wherever it is running. If the EJB class loader is the parent of the WAR class loader, when the helper
is used in the EJB container, it will only be able to load EJB classes and classes loaded by higher class
loaders. If the helper is used in the WAR, it will be able to load WAR classes as well.
Many frameworks, such as Web Work, use this approach to avoid problems caused by hierarchical class loading.
However, it's not usually required in application code, which should normally only load classes by name using an
abstraction layer that should conceal any use of the context class loader.


Class.forName(String clz);
使用调用这个语句的对象所使用的ClassLoader作为ClassLoader(1)。(请查看代码)

Thread.currentThread().getContextClassLoader())
返回当前线程使用的ClassLoader(2)。


如果ClassLoader(1)“等于”ClassLoader(2),那么这里的使用Class.forName(String clz)和ClassLoader(2).loadClass(String clz)就是等价的。

如果ClassLoader(1)“不等于”ClassLoader(2),那么就是不等价的。

在框架代码中,实际情况是ClassLoader(1)往往“不等于”ClassLoader(2):
即调用Class.forName(String clz)的语句所在的类的装载器不一定就是当前线程使用的类装载器。
因为:一个类装载完了在运行了,该类的所属的类装载器就确定了(不变),而在程序运行之中,线程
的类装载器都随时可以通过hread.currentThread().setContextClassLoader(loader)进行改变(变)。

==>一个不变,一个在变,当然就有可能不同了,所以banq说的对!
wangzhiliangofcn@yahoo.com.cn

我靠,时隔一年多后,终于得到肯定,心里还是很高兴,顶一下,很难的题目往往是看似简单,应用复杂的。

wangzhiliang 的原因也一语中的。

还是有区别的,
System.out.println(pa.getParent().getClass());
System.out.println(Thread.currentThread().getContextClassLoader().getClass());
在tomcat中第一行打出的是class org.apache.catalina.loader.StandardClassLoader
第二行打出的是
class org.apache.catalina.loader.WebappClassLoader

Jeff Hanson says that "By building a classloading component container framework that isolates Java class loading to a specified jar file, you can be confident that the runtime will load the component versions you expect." This can be a problem in J2EE environments, so understanding it is useful.


Take Control of Class Loading in Java :

http://www.theserverside.com/news/thread.tss?thread_id=40763

汗,虽然没有看懂很多内容,但是总算明白了一些事情:ClassLoader在一些系统级上的极端重要性.