阅读tomcat的源码之前有一些预备知识必须掌握,比如ClassLoader,因为我在看tomcat源码的入口类org.apache.catalina.startup.Bootstrap时,基本就是ClassLoaderFactory.createClassLoader(repositories, classLoader)在加载repositories中的*******.jar
tomcat启动过程中的类加载器层次结构图:
1 Java核心classloader
bootstrap
bootstrap classloader是由JVM启动的,用于加载%JAVA_HOME%/jre/lib/下的JAVA平台自身的类(比如rt.jar中的类等)。这个classloader位于JAVA类加载器链的顶端,是用C/C++开发的,而且JAVA应用中没有任何途径可以获取到这个实例,它是JDK实现的一部分
extension
entension classloader用于加载%JAVA_HOME%/jre/lib/ext/下的类,它的实现类是sun.misc.Launcher$ExtClassLoader,是一个内部类
2 system
System类加载器,也叫App类加载器,一般情况下,对于普通的JAVA应用,ClassLoader体系就到system为止了。平时编程时,甚至都不会感受到classloader的存在,但是对于其他一些应用,比如web server,插件加载器等,就必须和ClassLoader打交道了。这时候默认的类加载器不能满足需求了(类隔离、运行时加载等需求),需要自定义类加载器,并挂载到ClassLoader链中(默认会挂载到system classloader下面)
在tomcat里,默认情况下(通过setclasspath.sh修改CLASSPATH的值,而忽略环境变量中的CLASSPATH),会加载%CATALINA_HOME%/bin目录下的bootstrap.jar、tomcat-juli.jar、commons-daemon.jar ,此时tomcat就相关于一个App
3 Common
这个类加载器是tomcat特有的,对于所有web app可见。这个类加载器默认会加载%CATALINA_HOME%/lib下的所有jar包,这些都是tomcat的核心
4 WebappX
对于部署在容器中的每一个webapp,都有一个独立的ClassLoader,在这里实现了不同应用的类隔离
这里加载的就是我们熟悉的/WEB-INF/classes 和 /WEB-INF/lib下的jar
一般情况下ClassLoader是采用双亲委托模型加载类的,过程如下:
查找类所在位置,并将找到的Java类的字节码装入内存,生成对应的Class对象。Java的类装载器专门用来实现这样的过程,JVM并不止有一个类装载器,事实上,如果你愿意的话,你可以让JVM拥有无数个类装载器,当然这除了测试JVM外,我想不出还有其他的用途。
其实类装载器自身也是一个类,它也需要被装载到内存中来,那么这些类装载器由谁来装载呢,总得有个根吧?没错,确实存在这样的根,它就是神龙见首不见尾的Bootstrap ClassLoader. 为什么说它神龙见首不见尾呢,因为根本无法在Java代码中抓住哪怕是它的一点点的尾巴,尽管你能时时刻刻体会到它的存在,因为java的运行环境所需要的所有类库,都由它来装载,而它本身是C++写的程序,可以独立运行,可以说是JVM的运行起点。
在Bootstrap完成它的任务后,接着还会使用扩展类装载器ExtClassLoader,它用于装载Java运行环境扩展包中的类,然后会生成一个AppClassLoader,AppClassLoader可以通过调用ClassLoader.getSystemClassLoader() 来获得,假定程序中没有使用类装载器相关操作设定或者自定义新的类装载器,那么我们编写的所有java类通通会由它来装载。AppClassLoader查找类的区域就是耳熟能详的Classpath,按照它的类查找范围给它取名为类路径类装载器。
还是先前假定的情况,当Java中出现新的类,AppClassLoader首先在类传递给它的父类类装载器,也就是Extion ClassLoader,询问它是否能够装载该类,如果能,那AppClassLoader就不干这活了,同样Extion ClassLoader在装载时,也会先问问它的父类装载器。我们可以看出类装载器实际上是一个树状的结构图,每个类装载器有自己的父亲,类装载器在装载类时,总是先让自己的父类装载器装载,如果父类装载器无法装载该类时,自己就会动手装载,如果它也装载不了,就抛Exception,class not found。
当由直接使用类路径装载器装载类失败抛出的是NoClassDefFoundException异常。如果使用自定义的类装载器loadClass方法或者ClassLoader的findSystemClass方法装载类,如果你不去刻意改变,那么抛出的是ClassNotFoundException。(用过spring的朋友,配错类路径时肯定碰到过这个提示)
值得一提jdk官方文档里对getClassLoader()的描述中指出:
如果一个类是通过bootstrap 载入的,那我们通过这个类去获得classloader的话,有些jdk的实现是会返回一个null的,比如说我用 new Object().getClass().getClassLoader()的话,会返回一个null,这样的话上面的代码就会出现NullPointer异常.所以保险起见是使用我们自己写的类来获取classloader,"this.getClass().getClassLoader()“,这样一来就不会有问题。
tomcat的ClassLoader与标准的ClassLoader委托模型不同,在启动的时候的加载顺序为
Bootstrap--->System--->/WEB-INF/classes---> /WEB-INF/lib/*.jar---> Common
当webappLoader需要加载一个类的时候,首先是委托Bootstrap;然后尝试自行加载;接着是system;最后才会委托Common
from the perspective of a web application, class or resource loading looks in the following repositories, in this order:
- Bootstrap classes of your JVM
- /WEB-INF/classes of your web application
- /WEB-INF/lib/*.jar of your web application
- System class loader classes
- Common class loader classes
但如果在web.xml里配置了<Loader delegate="true"/>
委托顺序就会变成Bootstrap--》system--》Common--》尝试自行加载
- Bootstrap classes of your JVM
- System class loader classes
- Common class loader classes
- /WEB-INF/classes of your web application
- /WEB-INF/lib/*.jar of your web application
到目前为止,我还没搞明白为什么把Common放在最后,而不按正常的双亲委托模型来弄-.-!
tomcat官网有描述:
http://tomcat.apache.org/tomcat-8.0-doc/class-loader-howto.html
相关推荐
源码中的`classloader`目录揭示了这一机制。 9. **错误处理与日志系统**:Tomcat使用自定义的日志框架,源码中`logging`目录下的类定义了如何记录和处理错误信息。 10. **网络编程**:Tomcat底层使用NIO(非阻塞I/...
源码中,ClassLoader的实现(例如`org.apache.catalina.loader.WebappClassLoaderBase`)值得深入研究。 5. **部署和配置**:Tomcat支持多种方式部署Web应用,如WAR文件、目录结构或者通过管理接口。源码中,你可以...
Apache Tomcat 7.0.40 是一个广泛使用的开源软件,它是一个实现了Java Servlet、JavaServer Pages(JSP)和Java EE的Web应用程序容器。...对于Java Web开发人员来说,深入学习和理解Tomcat源码是提升技能的重要步骤。
【描述】中的“深入剖析Tomcat”是一本引导读者进行Tomcat源码阅读的书籍,通过这本书,你可以了解到Tomcat是如何处理HTTP请求,如何管理Web应用,以及如何进行线程调度等核心功能的。这本书的推荐表明,作者认为它...
5. **ClassLoader机制**:Tomcat使用自定义的ClassLoader来加载Web应用程序的类,确保不同应用之间的类隔离,防止冲突。 Tomcat 6.0.18版的特性包括: 1. **性能优化**:相对于之前的版本,6.0.18进行了性能调优,...
3. **启动流程**:Tomcat的启动过程始于`bin/catalina.sh`或`catalina.bat`,这些脚本会初始化Java环境,并加载`catalina.jar`中的`org.apache.catalina.startup.ClassLoader`,接着加载`Server`对象,初始化`...
了解并研究Tomcat源码对于深入理解Web服务器的工作原理,优化应用程序性能,以及解决可能出现的技术问题都具有重要意义。 1. **Servlet与JSP**: - **Servlet**:Servlet是Java编程语言中的一个接口,它定义了Web...
在这个项目中,开发者可能已经配置了相关的Maven插件和目标,以便于编译、测试和打包Tomcat源码。 【标签】: 1. **Tomcat8**:Tomcat 8是Tomcat服务器的第8个主要版本,它支持Java Servlet 3.1、JavaServer Pages...
通过研究Tomcat源码,开发者可以学习到如何构建一个高性能的Servlet容器,掌握Java Web应用的核心运行机制,这对于提升Java EE开发能力大有裨益。同时,如果你遇到Tomcat的使用问题或者想要进行定制化开发,源码分析...
《深入理解Tomcat 5.0.18 ClassLoader源码》 Tomcat作为一个流行的开源Java应用服务器,其内部机制的探究对于Java开发者而言具有重要的价值。尤其在类加载(Class Loading)机制方面,它是Java应用程序运行的基础,...
【标题】"Tomcat6的源码"涵盖了Java Web服务器Apache Tomcat的第六个主要版本的源代码。这个版本在2005年发布,它为开发者提供了深入了解Servlet和JSP容器工作原理的机会,同时也支持Java EE 5规范。Tomcat6是开源...
《深入剖析Tomcat8源码》 Tomcat8是一款广泛使用的开源Java Servlet容器,它实现了Java EE中的Web应用规范,包括Servlet、JSP和EL...对于Java EE开发者来说,掌握Tomcat源码无疑能够增强对整个Web栈的掌控力。
总的来说,《深入剖析Tomcat源码》这本书将带领我们探索Tomcat的每一个角落,从基础架构到高级特性,全面解析其设计思想和实现细节,帮助开发者更好地理解和优化自己的Java Web应用。通过学习和研究Tomcat源码,我们...
《Tomcat类加载机制——ClassLoader详解》 在Java Web开发中,Tomcat作为最常用的Servlet容器,其类加载机制对于...通过阅读和研究Tomcat源码,我们可以更深入地了解这一机制,从而更好地驾驭这个强大的Web服务器。