设为首页 收藏本站
查看: 1147|回复: 0

[经验分享] Tomcat类加载器体系结构

[复制链接]

尚未签到

发表于 2015-8-9 12:05:31 | 显示全部楼层 |阅读模式
与Java语言相似,Tomcat提供了分级类加载机制,当然,最顶端非BootStrap Loader莫属,它由C++编写,JVM启动且完成初始化后首先被调用。不过在Tomcat中类加载体系中,缺少了ExtClassLoader的身影(待验证),ExtClassLoader加载sun公司提供的扩展机制(参考文章:)。下面是架构图:
DSC0000.jpg    
上图展示了各层类加载器以及类文件搜索路径,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代码

  • private Object catalinaDaemon = null;//定义catalina服务器守护程序实例   
  •   
  • protected ClassLoader commonLoader = null;   
  • protected ClassLoader catalinaLoader = null;   
  • protected ClassLoader sharedLoader = null;   
  •   
  • private void initClassLoaders() {   
  •     try {   
  •         ClassLoaderFactory.setDebug(debug);   
  •         commonLoader = createClassLoader("common", null);   
  •         catalinaLoader = createClassLoader("server", commonLoader);   
  •         sharedLoader = createClassLoader("shared", commonLoader);   
  •     } catch (Throwable t) {   
  •         log("Class loader creation threw exception", t);   
  •         System.exit(1);   
  •     }   
  • }  
    private Object catalinaDaemon = null;//定义catalina服务器守护程序实例
protected ClassLoader commonLoader = null;
protected ClassLoader catalinaLoader = null;
protected ClassLoader sharedLoader = null;
private void initClassLoaders() {
try {
ClassLoaderFactory.setDebug(debug);
commonLoader = createClassLoader("common", null);
catalinaLoader = createClassLoader("server", commonLoader);
sharedLoader = createClassLoader("shared", commonLoader);
} catch (Throwable t) {
log("Class loader creation threw exception", t);
System.exit(1);
}
}
我们看到commonLoader的父类加载器为null,即在委派机制下它将把类加载任务直接委派给JVM所使用的BootStrap Loader,但为什么是null呢?因为JVM所使用的BootStrap Loader是用C++编写的。
catalinaDaemon为服务器从启动至停止都存在的守护线程,类似于桌面程序中的Main守护线程。createClassLoader函数利用ClassLoaderFactory类在工厂模式下创建,创建代码如下:





Java代码

  • public static ClassLoader createClassLoader(File unpacked[],File packed[], URL urls[], ClassLoader parent)throws Exception {   
  • ..   
  •        //获得将要创建的类加载器的类文件搜索路径   
  •        String array[] = (String[]) list.toArray(new String[list.size()]);   
  •        StandardClassLoader classLoader = null;   
  •        if (parent == null)//父加载器为JVM使用的BootStrap Loader   
  •            classLoader = new StandardClassLoader(array);   
  •        else  
  •            classLoader = new StandardClassLoader(array, parent);   
  •        classLoader.setDelegate(true);//设置该类加载器遵循委派模式   
  •        return (classLoader);   
public static ClassLoader createClassLoader(File unpacked[],File packed[], URL urls[], ClassLoader parent)throws Exception {
...
//获得将要创建的类加载器的类文件搜索路径
String array[] = (String[]) list.toArray(new String[list.size()]);
StandardClassLoader classLoader = null;
if (parent == null)//父加载器为JVM使用的BootStrap Loader
classLoader = new StandardClassLoader(array);
else
classLoader = new StandardClassLoader(array, parent);
classLoader.setDelegate(true);//设置该类加载器遵循委派模式
return (classLoader);
}
Tomcat提供两种类加载器供使用,一种是如上代码中所述的标准类加载器StandardClassLoader,用以实例化为commonLoader、catalinaLoader和sharedLoader,在org.apache.catalina.loader.StandardClassLoader定义,它不提供热部署功能;另外一种是专为Web程序所提供的WebClassLoader,它用以实例化为各部署项目的类加载器,在org.apache.catalina.loader.WebappClassLoader定义,提供热部署功能,也就是在发生ClassLoader搜索路径下的资源改变的动作之后,服务器自动重新加载之。
2、初始化catalina守护程序:





Java代码

  • public void init()   
  •     throws Exception   
  • {   
  •     // Set Catalina path   
  •     setCatalinaHome();   
  •     setCatalinaBase();   
  •       
  •     initClassLoaders();   
  •     Thread.currentThread().setContextClassLoader(catalinaLoader);   
  •     SecurityClassLoad.securityClassLoad(catalinaLoader);   
  •   
  •     /*利用类加载器catalinaClassLoader加载Catalina,并调用后者的process方法,该方法设置%CATALINA_HOME%,%CATALINA_BASE%,并根据参数配置启动catalina*/  
  •     Class startupClass =   
  •         catalinaLoader.loadClass   
  •         ("org.apache.catalina.startup.Catalina");   
  •     Object startupInstance = startupClass.newInstance();   
  •       
  •     /*将SharedClassLoader设为Catalina类的ClassLoader*/  
  •     String methodName = "setParentClassLoader";   
  •     Class paramTypes[] = new Class[1];   
  •     paramTypes[0] = Class.forName("java.lang.ClassLoader");   
  •     Object paramValues[] = new Object[1];   
  •     paramValues[0] = sharedLoader;   
  •     Method method =   
  •         startupInstance.getClass().getMethod(methodName, paramTypes);   
  •            
  •     method.invoke(startupInstance, paramValues);   
  •     catalinaDaemon = startupInstance;   
  • }  
    public void init()
throws Exception
{
// Set Catalina path
setCatalinaHome();
setCatalinaBase();
initClassLoaders();
Thread.currentThread().setContextClassLoader(catalinaLoader);
SecurityClassLoad.securityClassLoad(catalinaLoader);
/*利用类加载器catalinaClassLoader加载Catalina,并调用后者的process方法,该方法设置%CATALINA_HOME%,%CATALINA_BASE%,并根据参数配置启动catalina*/
Class startupClass =
catalinaLoader.loadClass
("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.newInstance();
/*将SharedClassLoader设为Catalina类的ClassLoader*/
String methodName = "setParentClassLoader";
Class paramTypes[] = new Class[1];
paramTypes[0] = Class.forName("java.lang.ClassLoader");
Object paramValues[] = new Object[1];
paramValues[0] = sharedLoader;
Method method =
startupInstance.getClass().getMethod(methodName, paramTypes);
method.invoke(startupInstance, paramValues);
catalinaDaemon = startupInstance;
}
本段代码实现了利用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/

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-96360-1-1.html 上篇帖子: tomcat内存溢出的解决方法(java.util.concurrent.ExecutionException: java.lang.OutOfMemoryEr 下篇帖子: Tomcat工作原理(小结)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表