tomcat类加载器及jar包冲突问题分析

1 篇文章 0 订阅
1 篇文章 0 订阅

tomcat类加载器及jar包冲突问题分析

开发过程中遇到过这样一个情况,在本地tomcat下开发调试正常,打包到测试环境的jboss下所有页面都变成空白页。
项目日志和jboss日志没有一点异常信息,费了半天劲把jboss所有日志全部打出来,发现是el.jar这个包里有空指针调用。
检查一下,项目WEB-INF\lib里有这个包呀,那应该是跟什么地方的jar包版本冲突了猜想,继续找,在jboss-4.0.5.GA\server\default\lib下找到了对应包,比较了一下版本果然版本不一样。
把项目下的el-api.jar,jsp-api.jar,servlet-api.jar删除,重新启动,问题解决。
接着有同事提出,同样在tomcat下开发也出现这种情况,经检查是他本地tomcat版本跟大家的不一致。开发环境这地方没做到很好的统一。

这样问题是解决了,但是有一点就想不明白了,按照java的类加载委托机制,推测应该是先从jboss-4.0.5.GA\server\default\lib加载,如果加载不到的话再用当前类加载器加载WEB-INF\lib下的jar包,所有如果jboss下有jar包WEB-INF\lib下的应该不起作用,也有不会有冲突了。
难到情况不是这样的?

一直想着找tomcat源码分析一下来着,拖了好久。赶上这两天不忙,就把apache-tomcat-6.0.33-src源文件弄了一份,debug看看到底怎样。
tomcat的类加载器结构和其他java项目是一致的。见图一


图一
其类图见图二

图二
elipse debug截图倒过来看跟这个就一样了。
Tomcat 通过Lifecycle接口来实现容器生命周期的统一管理,跟类加载器关系不大,这里就不讨论了。
通过这样大容器启动的时候启动子容器,逐级加载。其结构关系跟server.xml描述的基本一致,详细可以参考我的上一篇文章

Tomcat6结构分析
http://www.blogjava.net/zyskm/archive/2011/10/24/361870.html

(这个编辑工具不太会用,样式难看点,凑合看了)
每个容器都有自己的类加载器,在默认情况下都是StandardClassLoader的实例。
委托机制也和标准的java实现没什么两样。

接着往下看项目对应的类加载
StandardContext.start();调用WebappLoader.start()开始加载项目,WebappLoader又通过创建一个WebappClassLoader实例进行类加载。
WebappClassLoader.loadClass()实现依然波澜不惊,规规矩矩的先从缓存找,找不到调用findClass()进行加载。
果然这里实现有点不同,是先自己找,找不到再委托上级查找。和java默认的加载方式不同。
见源代码,只留下原理部分,日志和调试信息都去掉了。

public Class findClass(String name)  throws ClassNotFoundException  {
        // 先自己加载类,找不到则请求parent来加载,注意这点和java默认的委托模式不同
        Class clazz = null;
        try {
            if ((clazz == null)) {
                    clazz = findClassInternal(name);
            }

            if ((clazz == null) && hasExternalRepositories && !searchExternalFirst) {
                    clazz = super.findClass(name);
            }

            if (clazz == null{
                throw new ClassNotFoundException(name);
            }

        }
 catch (ClassNotFoundException e) {
            if (log.isTraceEnabled())
                log.trace("    --> Passing on ClassNotFoundException");
            throw e;
        }

        return (clazz);
}

据此可以认为,在web项目WEB-INF\lib下的jar包优先级高于jboss,tomcat 下的lib.
两处版本不一致的话会导致程序异常。
比较省事的办法是WEB-INF\lib下不再保留重复的jar包,实在闲着没事的话可以自己写个类加载器替换tomcat下WebappClassLoader改变加载顺序。
但是还可能有隐患,WebappClassLoader权限较低,它加载的类只能访问web应用下的资源,如果servlet-api.jar等包用到其他资源时可能出现异常。
这个没

实际测过,只是推测。但是catalina要提供对整个容器的支持,servlet-api实现对http协议的封装转换用到外部资源的可能性很大。


图三 类加载器结构图

总结:
sevlet-api.jar,jsp-api.jar,el-api.jar这类容器提供的jar包web项目下没必要再保留一份了,容易出现版本不一致。

附录:
查看tomcat源码的时候可以看看how tomcat works这本书,很不错,虽然老了点。

作者:zyskm 
http://www.blogjava.net/zyskm
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值