Understanding J2EE Application Server Class Loading Architectures
深刻理解J2EE服务器类加载架构

1.类加载是一种父子树形结构
2.父加载器是无法看到子加载器加载的类
3.如果同一个类被两个没有父子关系的并行同时加载,每个加载器有自己的实例,两个实例类型不兼容。
不同服务器不同类加载原理,文章讨论了WebLogic 6.1 with Service Pack 2 和WebSphere 4.0的classloader原理

http://www.theserverside.com/tt/articles/article.tss?l=ClassLoading

我看了DocumentBuilderFactory加载xml解析器后的理解:

首先,jdk考虑到不同app需要定制自己的classloader的情况(比如web应用),所以优先使用了thead的context classloader去加载类或者资源--如果只是使用class.forName,那么像这类需要加载具体实现的应用就只能在system classloader里找了,而具体实现(或者是实现的配置文件)可能在定制的classloader中(比如tomcat 的lib里面)。因此,jdk保证了我们在定制的classloader(比如web container)下也能正常使用使用xml解析器 :)

此外,在定制的classloader下加载自定义类时,万一调用者是system classloader的类时,使用class.forName就会找不到你的类--因为你的自定义类不在类路径里,这个时候也需要使用context classloader(不过这种情况比较少,主要可能是调用了系统的类来加载自定义的类,但是如果系统类没有使用context classloader那也无济于事:( 前一段时间用了jaxb,好像就没有用context classloader来加载类...)。

一般的classloader应该都需要用parent来优先代理查找类,这样才能保证加载层次逻辑上正确;所以context classloader应该是语义上最接近你的调用的loader,包含了相对最多的资源。

不知道理解的对不对*-) ...


以下是一点说明性的代码
-------------------


System.setProperty("jaxp.debug","1");
ClassLoader newClassLoader = Thread.currentThread().getContextClassLoader();
try {
//try commenting the following urlclassloader,you'll see the sun's default xml parser loaded
newClassLoader = new URLClassLoader(new URL[]{new URL(
"file:/D:/java/lib/xerces-

2.6.2.jar
")});
} catch (Exception e) {
e.printStackTrace();
}
ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(newClassLoader);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
Thread.currentThread().setContextClassLoader(oldClassLoader);

try {
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new ByteArrayInputStream(
"<root><a

id=\"id_a\">ael</a><b>bel</b></root>
".getBytes()));
System.out.println(document.getElementsByTagName(
"a").item(0).getTextContent());
} catch (Exception e) {
e.printStackTrace();
}

[该贴被floydd于2007年01月26日 00:16修改过]
[该贴被floydd于2007年01月26日 00:18修改过]

Class.forName,并不一定是通过当前线程的classloader加载类,还是有区别的,他应该和代码里直接引用该对象的加载机制一样,都是采用引用者的ClassLoader来加载引用。

比如:
Class.forName("java.lang.String");

String a ="";

加载方式是一样的。

所以,如果框架classloader层级关系复杂的话,就需要非常注意各个classloader之间的边界了

看到各位高手论道,我想顺便问个问题,好像也跟ClassLoader有关?希望能够得到解答,不胜感激!
我们在浏览器里插入APPLET,加载的时候需要时间,如果JAR够大,下载速度够慢就会让用户等很久而且没有进度提示,请问有什么可行的方法让我获取下载进度,或者获取到下载完成的事件
[该贴被zhubinwell于2007-12-20 18:59修改过]

板桥大哥帮忙看看来

banq老师您好,偶是一个java的初学者,无甚经验,偶然看到此贴,由于没有框架实践的经验所以确实找不到共鸣的感觉,但由于看到其他框架的代码中有相关的片段所以冒昧的问:

能否用类似如下的代码解决帖子中点到的问题呢?(尽管作为新人尚未看懂帖子的问题实指...)

try {
return Class.forName(className,
true,
Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e) {...throw e;}

可能是理解的不清晰吧(比如forName签名参数中的第二个boolean含义),所以也拟像您一样待到若干年后再回望此回复或许会领会与感悟.

????????????????

上面诸位有人说,大型系统中设计classLoader是因为,有些类之间不希望他们互相可见,所以用不同级别的classLoader来加载,我想问一下这个观点是针对实现功能而言的(不这么做就完成不了功能),还是针对项目管理而言的(控制应用层开发人员行为,指明名这个类的时候就不能用那个类)?我实在想破头也想不出来有什么必要让类之间不可见,比如假设jdk的所有库函数都在一个包里 还是像现在一样分在各个命名空间里,对我开发没有任何影响。。。。

佩服板桥大哥
精辟!
[该贴被xfzhu2003于2008-04-21 00:27修改过]

Class所在包是java.lang,java.lang包是由jdk启动后使用系统classloader加载的,Class.getClassloader取得的就是系统classloader,Thread.getcurrentThread.getclassloader就是加载当前线程对象的classloader, .getClass().getClassLoader()就是加载那个类的classloader

Class.forName(classname)默认是用调用 ClassLoader.getCallerClassLoader()这个方法来获得调用者类的加载器,而调用者的类加载器再利用classLoader的委托模型去加载。其实每次new一个类的时候,也是通过 ClassLoader.getCallerClassLoader()去获得调用者类的加载器来加载的。
Java中的类加载器可以分为四类:

1 Bootstrp loader
Bootstrp加载器是用C++语言写的,它是在Java虚拟机启动后初始化的,它主要负责加载%JAVA_HOME%/jre/lib以及%JAVA_HOME%/jre/classes中的类,并且它也会加载ExtclassLoader类。

2 ExtClassLoader
Bootstrp loader加载ExtClassLoader,并且将ExtClassLoader的父加载器设置为Bootstrp loader.当时因为bootstrp loader不是JAVA写的,所以占在JAVA的角度来看,调用Extclassloader的getParent()返回的是null.ExtClassLoader主要加载%JAVA_HOME%/jre/lib/ext中的jar文档,以及此路径下的所有classes目录。

3 AppClassLoader
Bootstrp loader加载完ExtClassLoader后,就会加载AppClassLoader,并且将AppClassLoader的父加载器指定为ExtClassLoader。AppClassLoader主要负责加载classpath所指定的位置的类或者是jar文档。

4 URLClassLoader
URLClassLoader是我们可以自定义的加载器,我们可以通过指定一个URL对象来创建此加载器,它所加载路径就是URL所代表的逻辑位置。并且它的父加载器是AppClassLoader。

有了这个加载器的继承体系以后,就可以清楚的知道委托模型是怎么实现的了,当一个加载器要加载一个类的时候,首先请求父加载器来加载,父加载器再请求父加载器来加载,依此类推,如果所有的父加载器都不能加载,那么才有自己加载,如果也不能加载,则出现NoClassDefFoundError错误.所以打包的时候,其实是将自己的类放在规定的地方,让框架已经实现的类加载器来加载,这样以来,就可以让框架来管理自己些的类的生命周期。在一般的情况下,我们自己写的类,默认都是由AppclassLoader来载入的,只要class的全名不和AppclassLoader的父加载器已经加载的类相同就OK。