Tomcat相关

95 阅读3分钟

Tomcat 的类加载方案

  • 引导类加载器 和 扩展类加载器 的作⽤不变;
  • 系统类加载器正常情况下加载的是 CLASSPATH 下的类,但是 Tomcat 的启动脚本并未使⽤该变量,⽽是加载tomcat启动的类,⽐如bootstrap.jar,通常在catalina.bat或者catalina.sh中指定。位于CATALINA_HOME/bin下;
  • Common 通⽤类加载器加载Tomcat使⽤以及应⽤通⽤的⼀些类,位于CATALINA_HOME/lib下,⽐如servlet-api.jar;
  • Catalina ClassLoader ⽤于加载服务器内部可⻅类,这些类应⽤程序不能访问;
  • SharedClassLoader ⽤于加载应⽤程序共享类,这些类服务器不会依赖;
  • WebappClassLoader,每个应⽤程序都会有⼀个独⼀⽆⼆的Webapp ClassLoader,他⽤来加载本应⽤程序 /WEB-INF/classes 和 /WEB-INF/lib 下的类。

tomcat 8.5 默认改变了严格的双亲委派机制:

  • 从缓存中加载;
  • 如果缓存中没有,会先调用ExtClassLoader进行加载, 扩展类加载器是遵循双亲委派的,他会调用bootstrap,查看对应的lib有没有,然后回退给ExtClassLoader对扩展包下的数据进行加载;
  • 如果未加载到,则从 /WEB-INF/classes加载;
  • 如果未加载到,则从 /WEB-INF/lib/*.jar 加载如果未加载到,WebAppclassLoader 会委派给SharedClassLoader,SharedClassLoad会委派给CommonClassLoader.....,依次委派给BootstrapClassLoader, 然后BootstrapClassLoader 在自己目录中查找对应的类如果有则进行加载,如果没有他会委派给下一级ExtClassLoader,ExtClassLoader再查找自己目录下的类,如果有则加载如果没有则委派给下一级……遵循双亲委派原则。

Web应用类加载器默认加载顺序如下:

(1)从缓存中加载。

(2)如果没有则从JVM的Bootstrap类加载器加载。

(3)如果没有则从当前类加载器加载(按照WEB-INF/classes、WEB-INF/lib的顺序)。

(4)如果没有则从父类加载器加载,由于父类加载器采用默认的委派模式,所以加载顺序为System、Common、Shared。

  1. 问题扩展  通过对上面tomcat类加载机制的理解,就不难明白为什么java文件放在Eclipse中的src文件夹下会优先jar包中的class?  这是因为Eclipse中的src文件夹中的文件java以及webContent中的JSP都会在tomcat启动时,被编译成class文件放在WEB-INF/class中。  而Eclipse外部引用的jar包,则相当于放在WEB-INF/lib中。  因此肯定是java文件或者JSP文件编译出的class优先加载。  通过这样,我们就可以简单的把java文件放置在src文件夹中,通过对该java文件的修改以及调试,便于学习拥有源码java文件、却没有打包成xxxsource的jar包。  另外呢,开发者也会因为粗心而犯下面的错误。  在CATALINA_HOME/lib以及WEB-INF/lib中放置了不同版本的jar包,此时就会导致某些情况下报加载不到类的错误。  还有如果多个应用使用同一jar包文件,当放置了多份,就可能导致多个应用间出现类加载不到的错误。