一、双亲委派机制
首先了解下双亲委派机制,大致过程如下:
简单来说,就是加载class文件时,委托上级加载器去加载,依次传递到顶层类加载器,加载过,直接返回;没加载过,尝试让下级进行加载,依次传递回去;
保证每个类只会被加载一次,避免重复加载。
二、分析
1、Tomcat需要隔离性
- 如果使用默认的类加载器,是无法加载两个相同类库不同版本的
- web容器部署多个应用程序,不同应用可能依赖相同类库不同版本,需要保证每个应用程序类独立、相互隔离
- 部署在同个web容器中的相同类库的相同版本可以共享,否则,会有重复的类库被加载进JVM
- web容器也有自己的类库,不能和应用程序的类库混淆,需要相互隔离
2、Tomcat需要热替换
jsp 文件其实也就是class文件,那么如果修改了,但类名还是一样,类加载器会直接取方法区中已经存在的,修改后的jsp是不会重新加载的
3、打破双亲委派机制
- OSGI是基于Java语言的动态模块化规范,类加载器之间是网状结构,更加灵活,但是也更复杂
- JNDI服务,使用线程上线文类加载器,父类加载器去使用子类加载器
三、Tomcat类加载器
1、拓展类加载器
说明如下:
- CommonClassLoader:tomcat最基本的类加载器,加载路径中的class可以被tomcat和各个webapp访问
- CatalinaClassLoader:tomcat私有的类加载器,webapp不能访问其加载路径下的class,即对webapp不可见
- SharedClassLoader:各个webapp共享的类加载器,对tomcat不可见
- WebappClassLoader:webapp私有的类加载器,只对当前webapp可见
每一个web应用程序对应一个WebappClassLoader,每一个jsp文件对应一个JspClassLoader,所以这两个类加载器有多个实例
2、工作原理
- a. CommonClassLoader能加载的类都可以被Catalina ClassLoader和SharedClassLoader使用,从而实现了公有类库的共用
- b. CatalinaClassLoader和SharedClassLoader自己能加载的类则与对方相互隔离
- c. WebAppClassLoader可以使用SharedClassLoader加载到的类,但各个WebAppClassLoader实例之间相互隔离,多个WebAppClassLoader是同级关系
- d. 而JasperLoader的加载范围仅仅是这个JSP文件所编译出来的那一个.Class文件,它出现的目的就是为了被丢弃:当Web容器检测到JSP文件被修改时,会替换掉目前的JasperLoader的实例,并通过再建立一个新的Jsp类加载器来实现JSP文件的HotSwap功能
tomcat目录结构,与上面的类加载器对应
- /common/*
- /server/*
- /shared/*
- /WEB-INF/*
默认情况下,conf目录下的catalina.properties文件,没有指定server.loader以及shared.loader,所以tomcat没有建立CatalinaClassLoader和SharedClassLoader的实例,这两个都会使用CommonClassLoader来代替。Tomcat6之后,把common、shared、server目录合成了一个lib目录。所以在我们的服务器里看不到common、shared、server目录
四、总结
Tomcat重写类加载器的主要目的是为了实现Web应用程序的隔离和热部署。
-
隔离性:Tomcat使用自定义的类加载器来加载每个Web应用程序的类。这样可以确保每个Web应用程序在运行时具有自己的类加载器实例,从而实现了应用程序之间的隔离。这样一来,不同的Web应用程序可以使用相同的类名,但它们的类加载器会将它们加载到各自的命名空间中,避免了类冲突的问题。
-
热部署:Tomcat的类加载器还支持热部署功能,即在应用程序运行时动态加载和卸载类。当Web应用程序的代码或资源发生变化时,Tomcat可以重新加载这些变化的部分,而无需重启整个服务器。这样可以提高开发和调试的效率。
通过重写类加载器,Tomcat能够实现更灵活的类加载和隔离机制,使得Web应用程序的部署和维护更加方便和高效。