JBoss、Tomcat Classloader不完全分析

http://seanhe.iteye.com/blog/841723

 

由于平时项目中用到的还是JBoss 4.2.x所以我这里的分析时针对这个版本的,不一定适用其他JBoss版本。
下面言归正传。
JBoss为了实现类的共享引入了class loader repository的概念,并且设计了org.jboss.mx.loading.UnifiedClassLoader3 (UCL)来完成sharing classes的主要功能。
UCL和UnifiedLoaderRepository3 一对多的关系,默认情况下一个jboss实例中只有一个UnifiedLoaderRepository3实例,这个UnifiedLoaderRepository实例会和所有的UCL关联。
NoAnnotationClassLoader是UCL的父classloader用来加载$JBOSS_HOME/lib下的jar,system class loader是NoAnnotationClassLoader的父classloader。
这几个对象的关系请见下图

从上图可以看出默认情况下所有的UCL共享一个Repository,通过Repository可以实现class的共享。 UnifiedLoaderRepository3实例中维护着两个容器,一个是class cache:这个容器很明显缓存了一些class,这样可以提高loadClass方法的执行效率;另一个是packagesMap:这个map维护的是 类的包名和UCL的mapping关系。具体UCL按什么逻辑load class的请看下面的活动图:

UnifiedClassLoader3的继承结构如下图所示,UnifiedClassLoader3的父类RepositoryClassLoader重写了URLClassLoader的loadClass方法,实现了上图的逻辑

下面请看一下相关代码:
RepositoryClassLoader.java

Java代码   收藏代码
  1. public Class loadClass(String name, boolean resolve)  
  2.       throws ClassNotFoundException  
  3.    {  
  4.       boolean trace = log.isTraceEnabled();  
  5.       if (trace)  
  6.          log.trace("loadClass " + this + " name=" + name+", loadClassDepth="+loadClassDepth);  
  7.       Class clazz = null;  
  8.       try  
  9.       {  
  10.          if (repository != null)  
  11.          {  
  12.             clazz = repository.getCachedClass(name);//先从cache中load class  
  13.             if (clazz != null)  
  14.             {  
  15.                if( log.isTraceEnabled() )  
  16.                {  
  17.                   StringBuffer buffer = new StringBuffer("Loaded class from cache, ");  
  18.                   ClassToStringAction.toString(clazz, buffer);  
  19.                   log.trace(buffer.toString());  
  20.                }  
  21.                return clazz;  
  22.             }  
  23.          }  
  24.          //loadClassImpl中会调用的LoadMgr3的一些方法实现上面流程图的逻辑,具体的代码实现比较冗长,这里就不贴出来了  
  25.          clazz = loadClassImpl(name, resolve, Integer.MAX_VALUE);  
  26.          return clazz;  
  27.       }  
  28.       finally  
  29.       {  
  30.          if (trace)  
  31.          {  
  32.             if (clazz != null)  
  33.                log.trace("loadClass " + this + " name=" + name + " class=" + clazz + " cl=" + clazz.getClassLoader());  
  34.             else  
  35.                log.trace("loadClass " + this + " name=" + name + " not found");  
  36.          }  
  37.       }  
  38.    }  


有几点结论可以加深一些印象:

  1. JBoss做为Application Server可以部署ear包也可以war包。但是jboss在默认情况下处理ear和war是两种class load机制。
  2. 当部署ear时,JBOSS默认使用我前面提到的class load机制。一个ear包里的所有的jar由一个UCL统一加载和管理
  3. 需要注意的是ear里的war的部署有点特别。它只是将自身添加到ucl的classpath域中,而war下的WEB-INF/lib/*.jar,则是由WebAppClassloader来加载


由于jboss对所有UCL的共享机制就会导致出现一些class的版本冲突问题,一些应用加载不到自己的应用需要的class。对于这个问题JBOSS提供了一些解决措施:http://community.jboss.org/wiki/ClassLoadingConfiguration。后面我会再整理一下此前我遇到过的一个class冲突的case和解决办法。

Tomcat6/7 class loader机制
Tomcat class loader层次结构

Tomcat的class load机制较Jboss来说要简单
当web应用需要load class时先调用WebAppClassloader的loadClass方法,loadClass内部逻辑如下:

  1. 调用findLoadedClass(String)检查此class是否已经加载,如果以加载则直接返回,如果没有则继续做下一步。
  2. 调用system class loader的loadClass的方法,这样可以加载到JDK核心的类,如果没有找到符合的类则继续做下一步。
  3. 如果WebAppClassloader的delegate属性是true或者正在处理的class在过滤列表里,会先从父class loader中加载类。如果没有则继续做下一步。一般这一步不会执行。
  4. WebAppClassloader在自己的类库(WEB-INF/classes和WEB-INF/lib)中查找class。如果没有则继续做下一步。
  5. 如果前面第3步已经跳过这一步会继续执行。如果前面第3步已经执行过,这一步就不会再执行。这一步的执行逻辑同第3步。


具体的代码可以看WebAppClassloader.loadClass(..)

 


参考文档:
http://community.jboss.org/wiki/JBossClassLoadingUseCases
http://community.jboss.org/wiki/ClassLoadingConfiguration
http://community.jboss.org/wiki/EnableClassloaderLogging
http://agapple.iteye.com/blog/791940

http://www.iteye.com/topic/826661

转载于:https://www.cnblogs.com/lingxue3769/archive/2012/03/01/2375997.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值