Tomcat类加载器体系结构

   与Java语言相似,Tomcat提供了分级类加载机制,当然,最顶端非BootStrap Loader莫属,它由C++编写,JVM启动且完成初始化后首先被调用。不过在Tomcat中类加载体系中,缺少了ExtClassLoader的身影(待验证),ExtClassLoader加载sun公司提供的扩展机制(参考文章: <<Extension Mechanism Architecture>> )。下面是架构图: 

 
上图展示了各层类加载器以及类文件搜索路径,Tomcat为每个部署到其中的Web项目定义一个类加载器(如上图中WebappAClassLoader、WebappBClassLoader),其类文件搜索路径即为%CATALINA_HOME%\webapps\项目名称\WEB-INF\lib\; 
%CATALINA_HOME%\webapps\项目名称\WEB-INF\classes\。Tomcat自己定义了一个BootStrap类,在org.apache.catalina.startup.BootStrap定义,其作用是: 
1、定义公共类加载器  
Java代码   收藏代码
  1. private Object catalinaDaemon = null;//定义catalina服务器守护程序实例  
  2.   
  3. protected ClassLoader commonLoader = null;  
  4. protected ClassLoader catalinaLoader = null;  
  5. protected ClassLoader sharedLoader = null;  
  6.   
  7. private void initClassLoaders() {  
  8.     try {  
  9.         ClassLoaderFactory.setDebug(debug);  
  10.         commonLoader = createClassLoader("common"null);  
  11.         catalinaLoader = createClassLoader("server", commonLoader);  
  12.         sharedLoader = createClassLoader("shared", commonLoader);  
  13.     } catch (Throwable t) {  
  14.         log("Class loader creation threw exception", t);  
  15.         System.exit(1);  
  16.     }  
  17. }  

我们看到commonLoader的父类加载器为null,即在委派机制下它将把类加载任务直接委派给JVM所使用的BootStrap Loader,但为什么是null呢?因为JVM所使用的BootStrap Loader是用C++编写的。 
catalinaDaemon为服务器从启动至停止都存在的守护线程。createClassLoader函数利用ClassLoaderFactory类在工厂模式下创建,创建代码如下: 
Java代码   收藏代码
  1. public static ClassLoader createClassLoader(File unpacked[],File packed[], URL urls[], ClassLoader parent)throws Exception {  
  2. ..  
  3.        //获得将要创建的类加载器的类文件搜索路径  
  4.        String array[] = (String[]) list.toArray(new String[list.size()]);  
  5.        StandardClassLoader classLoader = null;  
  6.        if (parent == null)//父加载器为JVM使用的BootStrap Loader  
  7.            classLoader = new StandardClassLoader(array);  
  8.        else  
  9.            classLoader = new StandardClassLoader(array, parent);  
  10.        classLoader.setDelegate(true);//设置该类加载器遵循委派模式  
  11.        return (classLoader);  

Tomcat提供两种类加载器供使用,一种是如上代码中所述的标准类加载器StandardClassLoader,用以实例化为commonLoader、catalinaLoader和sharedLoader,在org.apache.catalina.loader.StandardClassLoader定义,它不提供热部署功能;另外一种是专为Web程序所提供的WebClassLoader,它用以实例化为各部署项目的类加载器,在org.apache.catalina.loader.WebappClassLoader定义,提供热部署功能,也就是在发生ClassLoader搜索路径下的资源改变的动作之后,服务器自动重新加载之。 
2、初始化catalina守护程序:  
Java代码   收藏代码
  1. public void init()  
  2.     throws Exception  
  3. {  
  4.     // Set Catalina path  
  5.     setCatalinaHome();  
  6.     setCatalinaBase();  
  7.       
  8.     initClassLoaders();  
  9.     Thread.currentThread().setContextClassLoader(catalinaLoader);  
  10.     SecurityClassLoad.securityClassLoad(catalinaLoader);  
  11.   
  12.     /*利用类加载器catalinaClassLoader加载Catalina,并调用后者的process方法,该方法设置%CATALINA_HOME%,%CATALINA_BASE%,并根据参数配置启动catalina*/  
  13.     Class startupClass =  
  14.         catalinaLoader.loadClass  
  15.         ("org.apache.catalina.startup.Catalina");  
  16.     Object startupInstance = startupClass.newInstance();  
  17.       
  18.     /*将SharedClassLoader设为Catalina类的ClassLoader*/  
  19.     String methodName = "setParentClassLoader";  
  20.     Class paramTypes[] = new Class[1];  
  21.     paramTypes[0] = Class.forName("java.lang.ClassLoader");  
  22.     Object paramValues[] = new Object[1];  
  23.     paramValues[0] = sharedLoader;  
  24.     Method method =  
  25.         startupInstance.getClass().getMethod(methodName, paramTypes);  
  26.           
  27.     method.invoke(startupInstance, paramValues);  
  28.     catalinaDaemon = startupInstance;  
  29. }  

本段代码实现了利用CatalinaClassLoader加载Catalina类,并创建其实例。但很有意思的是,创建实例之后Catalina的类加载器却被设置为SharedClassLoader。 
我们知道Catalina是Tomcat容器的代言人,也就是一个在容器生命周期内都存在的类,我们所设计的Servlet是被放置在这个容器里面供调用的,从代码层来讲也就是被实例化,然后引用。同时,在Java类加载器体系结构中定义到:被引用类默认由依赖类的ClassLoader加载,而这样设计的原因是,运行时相同层次的ClassLoader所加载的类无法看到其他ClassLoader所加载的类,可这又是为什么呢?这是Java语言的安全特性所要求的(进一步探讨,请参阅《深入Java虚拟机》)。由上所述,可以知道如果要引用Servlet的话,得有Catalina的ClassLoader出马去加载,但是我们之前已经看到了,每一个Web项目都有一个特定的WebappClassLoder加载,并且Catalina需要引用的可是同时部署到其中的许多个Web项目的Servlet,这就出现了矛盾。但是,我们仔细看看WebappClassLoader的设计,它的父加载器可是SharedClassLoader哦(SharedClassLoader加载的是部署到容器中的多个Web项目共用的资源),故聪明的小花猫把Catalina的类加载器设置为了SharedClassLoader,这样利用父加载器加载Catalina,而子加载器来加载Servlet,岂不是一个绝妙的设计! 
注意 :代码中利用到了强大的反射机制。 

延伸探究: 
http://blog.chinaunix.net/u2/83532/showart_1418390.html  
http://blog.163.com/haizai219@126/blog/static/44412555200810111429791/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值