Tomcat类加载器
java本身的类加载器是双亲委派机制,而tomcat的应用场景是需要web应用类库隔离的,为了避免应用包之间相互影响,所以java原生的双亲委派是不可以在tomcat中使用了

tomcat类加载器
可以看到tomcat实现了自己的类加载器模型,在catalina.properties中进行配置
1 | "${catalina.base}/lib","${catalina.base}/lib/*.jar","${catalina.home}/lib","${catalina.home}/lib/*.jar" = |
只有指定了server.loader和shared.loader才会真正建立Catalina类加载器和Shared类加载器的实例
Common 以System为父类加载器,位于tomcat应用服务器顶层的公用类加载器,使用common.loader进行配置。可以负责加载Tomcat应用服务器内部和Web应用均可见的类,如Servlet规范相关包以及一些通用的工具包
Catalina 以common为父加载器,用于加载tomcat应用服务器的类加载器,使用server.loader进行配置,默认为空,即使用common类加载器加载应用服务器。可以负责加载只有Tomcat应用服务器内部可见的类,这些类对Web应用不可见
Shared 以common为父加载器,是所有web应用的父加载器,使用shared.loader进行配置,默认为空,即使用common类加载器作为web应用的父加载器。可以负责加载web应用共享的类,但是对Tomcat自己不可见
Web应用 以Shared为父加载器,加载/WEB-INF/classes目录下的未压缩的class和资源文件以及/WEB-INF/lib下的jar包,只对当前web应用可见,tomcat和其他web应用不可见
servlet只允许载入WEB-INF/classes目录以及其子目录下的类,而不能载入所有类库,每个应用的加载器仅限于Context级别的servlet容器
Tomcat实现自定义加载器的另一个原因是需要提供自动重载的功能,当WEB-INF/classes目录或WEB-INF/lib目录下的类发生变化时,web应用程序需要重新载入这些类
需要使用一个线程来不断地检查这些类文件的时间戳
加载过程
当进行类加载时,除JVM基础类库外,会首先尝试通过当前类加载器加载,然后才会进行委派。Servlet规范相关的API禁止通过Web应用类加载器加载。因此,不要在web应用中包含这些包。如servlet-api.jar
WebappClassLoaderBase#loadClass
1 | public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { |
WebappClassLoaderBase#findClass
1 | public Class<?> findClass(String name) throws ClassNotFoundException { |
Web应用类加载器默认加载顺序为
- 先从缓存中加载
- 如果没有,则从JVM的Bootstrap类加载器中加载
- 如果没有,则从当前类加载器加载(按照WEB-INF/classes、WEB-INF/lib的顺序)
- 如果没有,则从父类加载器加载,父类加载器采用默认的委派方式,加载顺序为System->Common->Shared
当然了,如果就想使用java原生的委派机制怎么办呢
可以看之前文章 tomcat之server配置文件的Loader节点
将delegate改为true即为使用java原生的委派机制,此时的加载顺序为
- 先从缓存中加载
- 如果没有,则从JVM的Bootstrap类加载器中加载
- 如果没有,则从父类加载器加载,父类加载器采用默认的委派方式,加载顺序为System->Common->Shared
- 如果没有,则从当前类加载器加载(按照WEB-INF/classes、WEB-INF/lib的顺序)
v1.3.10