Classloader委任机制以及Tomcat中Classloader分析(整理)

参照网页

http://hi.baidu.com/qmiao128/item/c983bffca5ca6fec1b111f26

http://m.oschina.net/blog/144133

http://blog.csdn.net/feng2007110221053/article/details/7071823


Java中一共有四个类加载器,之所以叫类加载器,是程序要用到某个类的时候,要用类加载器载入内存。

 

这四个类加载器分别为:Bootstrap ClassLoader、Extension ClassLoader、AppClassLoader

和URLClassLoader,他们的作用其实从名字就可以大概推测出来了。

其中AppClassLoader在很多地方被叫做System ClassLoader

 

(1).BootStrap ClassLoader:启动类加载器,由C++代码实现,负责加载存放在%JAVA_HOME%\lib目录中的,或者通被-Xbootclasspath参数所指定的路径中的,并且被java虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库,即使放在指定路径中也不会被加载)类库到虚拟机的内存中,启动类加载器无法被java程序直接引用。

 

(2).Extension ClassLoader:扩展类加载器,由sun.misc.Launcher$ExtClassLoader实现,负责加载%JAVA_HOME%\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器。

 

(3).Application ClassLoader:应用程序类加载器,由sun.misc.Launcher$AppClassLoader实现,负责加载用户类路径classpath上所指定的类库,是类加载器ClassLoader中的getSystemClassLoader()方法的返回值,开发者可以直接使用应用程序类加载器,如果程序中没有自定义过类加载器,该加载器就是程序中默认的类加载器。

 

(4).URLClassLoader用来加载网络上远程的类,暂且不讨论。

 

它们之间的关系:

1.Parent-Child,按顺序从大到小。不是简单的继承关系。

 

2.ClassLoader有个getParent的方法,但是Ext ClassLoader调用后得到的是null,bootstrap是JVM自己的,用户看不到。

 

3.classloader的委托机制:当等级比较低的ClassLoader要加载某个类的时候,它首先会请求Parent加载器来加载,Parent再请求它的Parent。

比如现在Ext要加载了,它往上请求。如果最大的Bootstrap找不到,那么Boot会叫Ext自己找找,Ext找不到,是不会让下一级的App去找的,此时就报出ClassNotFoundException

 

4.类A调用类B,B会要求调用它的类的类加载器来加载它,也就是B会要求加载A的加载器来加载B。

这就会有个问题,如果他们在一起,那没关系,肯定某个classloader会把它们俩都加载好。

但是如果A在/lib/ext文件夹中,而B在Classpath中呢?

过程是这样的:

首先加载A,那么一层层上到Bootstrap Classloader,boot没找到所以ext自己找,找到了,没问题;

加载B,因为A调用了B,所以也从bootstrap来找,没找到,然后A的ext classloader来找还是没找到,但是再也不会往下调用了,于是报出ClassNotFoundException。

 

但是现实生活中有很多应用,比如JDBC核心方法在核心库,而驱动在扩展库,是必定在两个地方的,那怎么办呢?

要用到Context ClassLoader:我们在建立一个线程Thread的时候,可以为这个线程通过setContextClassLoader方法来指定一个合适的classloader作为这个线程的context classloader,当此线程运行的时候,我们可以通过getContextClassLoader方法来获得此context classloader,就可以用它来载入我们所需要的Class。默认的是system classloader。

 

利用这个特性,我们可以“打破”classloader委托机制了,父classloader可以获得当前线程的context classloader,而这个context classloader可以是它的子classloader或者其他的classloader,那么父classloader就可以从其获得所需的 Class,这就打破了只能向父classloader请求的限制了。

 

这个机制可以满足当我们的classpath是在运行时才确定,并由定制的 classloader加载的时候,由system classloader(即在jvm classpath中)加载的。

class可以通过context classloader获得定制的classloader并加载入特定的class(通常是抽象类和接口,定制的classloader中是其实现)。

 

Tomcat5中类加载器分析

tomcat5中通过自定义一组类加载器,解决了以下几个问题:

(1)部署在一个服务器上的两个Web应用程序自身所使用的Java类库是相互隔离的。

(2)部署在一个服务器上的两个Web应用程序可以共享服务器提供的java共用类库。

(3)服务器尽可能的保证自身安全不受部署的Web应用程序影响。

(4)支持对JSP的HotSwap功能。

 

tomcat5的目录结构

tomcat5主要根据根据java类库的共享范围,分为4组目录:

(1)common目录:能被Tomcat和所有Web应用程序共享。

(2)server目录:仅能被Tomcat使用,其他Web应用程序不可见。

(3)Shared目录:可以被所有Web应用程序共享,对Tomcat不可见。

(4)WEB-INF目录:只能被当前Web应用程序使用,对其他web应用程序不可见。

 

tomcat5自定义类加载器

 
Classloader委任机制以及Tomcat中Classloader分析(整理)
 

这几个类加载器分别对应加载/common/*、/server/*、/shared/*和 /WEB-INF/*类库, 其中Webapp类加载器和Jsp类加载器会存在多个,每个Web应用对应一个Webapp类加载器。

 

CommonClassLoader加载的类可以被CatalinaClassLoader和ShareClassLoader使用;

CatalinaClassLoader加载的类和ShareClassLoader加载的类相互隔离;

WebappClassLoader可以使用ShareClassLoader加载的类,但各个WebappClassLoader间相互隔离;JspClassLoader仅能用JSP文件编译的class文件。

 

Tomcat5动时classloader载顺

Tomcatclass序一

1.最先是$JAVA_HOME/jre/lib/ext/下的jar文件。

2.CLASSPATH中的jarclass文件。

3.$CATALINA_HOME/common/classes下的class文件。

4.$CATALINA_HOME/commons/endorsed下的jar文件。

5.$CATALINA_HOME/commons/i18n下的jar文件。

6.$CATALINA_HOME/common/lib 下的jar文件。

JDBC驱动jar文件可以放在里,这样就可以避免在server.xml配置好数据源却出找不到JDBC Driver的情况。)

7.$CATALINA_HOME/server/classes下的class文件。

8.$CATALINA_HOME/server/lib/下的jar文件。

9.$CATALINA_BASE/shared/classes 下的class文件。

10.$CATALINA_BASE/shared/lib下的jar文件。

11.各自具体的webapp /WEB-INF/classes下的class文件。

12.各自具体的webapp /WEB-INF/lib下的jar文件。

 

关于WEB-INF/classesWEB-INF/libload优先顺序,weblogic中,可以通过修正WebContent\WEB-INF\weblogic.xml中的如下参数来设定。

<!-- web-inf/classes里面优于lib加载 -->
<prefer-web-inf-classes>true</prefer-web-inf-classes>

 

最后,思考两个问题:

1.当某个properties文件同时存在于/shared/*类库下的jarWEB-INF/classes中时,会优先load哪一个呢?

  答案是放在/shared/*类库下的jar中的那个。

2.当某个properties文件同时存在于WEB-INF/classesWEB-INF/libjar文件中时,会优先load哪一个呢?

  答案是放在WEB-INF/classes中的那个。

你可能感兴趣的:(jvm,tomcat,ClassLoader)