http://freewind886.blog.163.com/blog/static/6619246420126141074308/
上周有用户在试用产品里一个与自定义classloader相关的功能时,发现在Junit下运行正常,部署到tomcat运行就会报错。
功能概述如下:
用户根据需要在可视界面上编写一个接口Hash的实现类,然后源码经过动态编译(借助jdk中的tools.jar包)在临时文件夹中生成class文件,读取该文件进入内存就可以存到数据库或者通过网络发送到其他Java进程。其他进程获取到class文件的byte[]后,通过一个自定义的classloader就可以创建出类实例。
现在的问题就在于这个自定义的classloader在Junit下可以加载byte[]创建类实例,而在tomcat下则抛出加载错误。之前曾了解过tomcat下的类加载机制和常见的Java应用不一样,所以开始的时候估计问题应该是出在这个地方,后来同事在断点调试下也明确了问题的原因。
推荐看这篇文章,里面详细介绍了Java的类加载机制:http://www.ibm.com/developerworks/cn/java/j-lo-classloader/
借用里面的一张图:
对于直接通过java命令启动的Java应用,classpath里的类都由系统类加载器加载到进程中。我们产品中的自定义类加载器MyClassLoader在加载class文件的byte[]时,会检测到该类引入了接口Hash,MyClassLoader会将Hash的加载代理给父加载器(系统类加载器),系统类加载器在classpath中找到Hash的定义然后加载,接着整个加载操作就可以顺利的完成。
在tomcat环境下,类加载的机制就不同了,具体可见 http://blog.163.com/haizai219@126/blog/static/44412555200810111429791/
借用一图如下:
Bootstrap
|
System
|
Common
/ \
Catalina Shared
/... ...\
webapp1 webappN
在这种架构下,应用的类都由webappX类加载器来加载,而自定义的类加载器MyClassLoader的父加载器也就应该是webappX,那在加载网络传送过来的类定义的时候,也不会出现问题。最后在定位问题的时候,就是发现MyClassLoader的父加载器不是webappX,而是System,即上面提到的系统类加载器。
MyClassLoader(内部类)的实现如下:
privatestaticclassMyClassLoaderextendsClassLoader{
privatebyte[] classData =null;
privateMyClassLoader(){
super();
}
protectedClass<?> findClass(String name){
return defineClass(name,this.classData,0,this.classData.length);
}
privateObject newInstance(String name)throwsInstantiationException,
IllegalAccessException,ClassNotFoundException{
return loadClass(name,true).newInstance();
}
}
查看ClassLoader的无参构造函数,可以看到一行代码 this.parent = getSystemClassLoader(); 这就是说,如果自定义的classloader如果不指定父加载器,则会被默认设置为系统类加载器。这就是问题的所在。 当MyClassLoader在加载Hash的实现类定义时,让父加载器(系统类加载器)去加载Hash接口定义。在tomcat的类加载机制下,系统类加载器实际上并不能加载应用功能相关的类,这就导致加载Hash失败。
修改的方法就是在创建MyClassLoader的时候,传入合适的父加载器。可以找一个使用了MyClassLoader的类,通过Class.getClassLoader()获取到所应该依附的父加载器。这样在tomcat或者普通的Java应用都可以解决加载出错的问题。
相关推荐
- **Web容器**:现代Web容器(如Tomcat、Jetty等)广泛使用类加载器来支持多应用共存环境下的隔离性,每个Web应用都有自己的类加载器,这样可以避免不同应用之间的类冲突问题。 - **OSGi**:OSGi是一个Java平台的...
在一些特定的应用场景下,如 Tomcat 服务器,会使用更为复杂的类加载器架构。例如,Tomcat 使用了多种类加载器来处理不同的类资源: 1. **CommonClassLoader**: - 负责加载 `/common/*` 目录中的类。 2. **...
为了避免这类问题,建议保持项目依赖的一致性,尽量避免使用自定义的类加载器或重写库中的类。同时,使用版本管理工具,如Maven或Gradle,可以帮助更好地管理和控制依赖关系,减少类冲突的可能性。 最后,关于...
- Tomcat使用自定义的类加载器,如`CommonClassLoader`、`CatalinaClassLoader`等,它们按照特定的层次结构加载类。 5. **初始化容器** - `Catalina`类是Tomcat的主要组件,负责管理所有Web应用。在启动过程中,...
Tomcat使用自定义的类加载器来加载Web应用中的类,以实现不同应用之间的类隔离。主要有CommonClassLoader、SharedClassLoader和WebappClassLoader,它们按层次加载类。 5. **连接器(Connector)与协议处理器...
2. **类加载机制**:Tomcat使用自定义的类加载器,如`CommonClassLoader`、`WebappClassLoader`等,以实现不同Web应用间的隔离。 3. **请求处理**:` CoyoteAdapter`是Servlet容器与Tomcat网络接口(Coyote)之间的...
同时,Tomcat还提供了自定义的类加载策略,例如,可以通过配置`catalina.properties`来改变类加载的顺序,或者通过实现`org.apache.catalina.Loader`接口来自定义加载器的行为。 了解Tomcat的ClassLoader源码,有助...
Tomcat7源码还涉及到了类加载机制,它采用了自定义的类加载器,如`CatalinaClassLoader`和`SharedClassLoader`,理解这些类加载器的工作方式有助于解决类冲突和加载顺序问题。 此外,Tomcat的安全管理也是重要一环...
8. **类加载器**:Tomcat有自己独特的类加载机制,以解决不同应用之间的类冲突。源码中的`classloader`目录揭示了这一机制。 9. **错误处理与日志系统**:Tomcat使用自定义的日志框架,源码中`logging`目录下的类...
这些问题可能包括端口被占用、配置文件错误、类加载器相关问题等。通过对这些问题的分析,我们可以更加深入地理解Tomcat的工作机制,以及其在不同环境下可能遇到的问题和解决方案。 3. 架构探讨:Tomcat拥有清晰的...
这涉及到Web-INF/classes和lib目录的加载顺序,以及“common”、“catalina”、“shared”类加载器的角色。 5. **Servlet生命周期**:在Eclipse工程中,理解Servlet的初始化、服务、销毁过程,以及如何通过注解或...
类加载是另一个关键点,Tomcat使用自定义的类加载器来确保不同Web应用之间的类隔离,避免冲突。每个Context有一个私有的类加载器,优先加载自己的类,然后是其父类加载器,直到系统类加载器。这种层次结构确保了类的...
3. 如果项目中使用了自定义的类加载器(ClassLoader),则需要检查自定义类加载器的实现是否正确。自定义类加载器可能会影响JAR包的加载顺序和方式,有时可能会导致Tomcat无法正确找到或识别JAR包。 4. 对于使用了...
你需要设计一个自定义的类加载器来处理这个问题。 7. **安全与配置**:最后,一个成熟的Web服务器还需要考虑安全性,如SSL/TLS支持,以及提供配置文件供管理员调整服务器行为。 【标签】"源码","工具" 通过研究...
Tomcat作为Servlet容器,负责加载、执行和管理Servlet,使得开发者可以使用Java语言构建动态Web应用。 3. **JSP (JavaServer Pages)**:JSP是Java EE平台的一部分,它允许开发人员在HTML代码中嵌入Java代码,以生成...
6. **可扩展性**:Tomcat允许添加自定义Valves(请求处理组件)、Connectors(连接器)和Realm(认证模块),以满足特定的需求或集成其他系统。 7. **文档齐全**:Apache Tomcat提供了详尽的官方文档,包括安装指南...
《深入理解Tomcat:工作原理与源码剖析》 Tomcat作为一款开源的Java Servlet容器,是Apache软件基金会...在实际应用中,结合官方文档和社区资源,我们可以解决遇到的各类问题,让Tomcat更好地服务于我们的项目。
5. **ClassLoader**:Tomcat使用自定义的ClassLoader来加载Web应用的类。这使得不同应用之间能隔离地运行,避免类冲突。 6. **Lifecycle**:所有Tomcat组件都遵循生命周期接口,如`org.apache.catalina.Lifecycle`...
开发者需要确保所有必要的JAR文件已正确地放置在`lib`目录下,或者通过类加载器从外部路径加载。 9. **扩展性**:Tomcat v8.0允许开发者通过插件和自定义监听器、过滤器等扩展其功能。开发者可以根据需求编写自己的...