tomcat类加载器及jar包冲突问题分析
来源:互联网 发布:网络视频广告的特点 编辑:程序博客网 时间:2024/06/05 05:18
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);
}
// 先自己加载类,找不到则请求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等包用到其他资源时可能出现异常。
这个没
图三 类加载器结构图
总结:
sevlet-api.jar,jsp-api.jar,el-api.jar这类容器提供的jar包web项目下没必要再保留一份了,容易出现版本不一致。
附录:
查看tomcat源码的时候可以看看how tomcat works这本书,很不错,虽然老了点。
作者:zyskm
http://www.blogjava.net/zyskm
0 0
- tomcat类加载器及jar包冲突问题分析
- tomcat类加载器找不到jar包中的类问题分析与解决思路
- Tomcat部署项目jar包冲突问题
- tomcat jar包冲突
- Jboss jar包冲突及jar加载顺序
- Jboss jar包冲突及jar加载顺序
- myeclipse+tomcat jar包冲突导致jsp编译问题及/WEB-INF/lib/ servlet-api.jar) - jar not loaded 问题
- 通过类加载器解决jar包冲突(一)
- YARN环境中应用程序JAR包冲突问题的分析及解决
- 项目中jsp-api.jar 包与tomcat冲突问题
- 重新看待Jar包冲突问题及解决方案
- 解决jar包冲突问题
- ssh- jar 包冲突问题
- es jar包冲突问题
- tomcat启动jar包加载
- Tomcat同一目录下jar包加载顺序问题
- java动态加载指定的类或者jar包反射调用其方法-涉及其他jar中的类就报ClassNotFound问题分析及解决思路
- java动态加载指定的类或者jar包反射调用其方法-涉及其他jar中的类就报ClassNotFound问题分析及解决思路
- 使用GitHub部署项目并将网站免费挂到github上
- 进程与线程的区别
- Basic Interior in Unreal Engine 4.12
- 带宽的深入理解
- 前端chrome浏览器调试总结(转载于cayley的编程之路)
- tomcat类加载器及jar包冲突问题分析
- ubuntu上安装MySQL
- I/O多路复用- select函数
- Mac使用技巧——Homebrew与Homebrew Cask
- CodeForces - 719E Sasha and Array 线段树 + 矩阵快速幂
- Maven新建webapp项目index.jsp报错
- easyui_json
- 【POJ2396】Budget(有源汇的上下界可行流)
- 复制构造函数学习笔记