首先回答一个问题,tomcat为什么要设计自己的类加载机制?
我们用反证法来解答一下这个问题。tomcat是一个servlet容器,加载servlet类需要一个类加载器,
如果不用自己的类加载器,那么会使用默认的AppClassLoader
,但是使用
AppClassLoader
会带来一些问题,具体说来:
Java标准的类加载器及其双亲委派机制是
AppClassLoader -> ExtClassLoader -> BootstrapClassLoader
, 其中AppClassLoader
是系统默认的类加载器
因为一个tomcat下可以同时部署多个项目(或者说应用),项目于项目之间的servlet类 需要互相隔离开,如果使用AppClassLoader则所有项目共享相同的类路径(CLASSPATH),项目于项目的源码之间 无法实现隔离,可能造成严重的安全问题,因此tomcat需要解决这个问题,
同时为了支持reloadable,reloadable是这样一项技术,如果项目下WEB-INF/classes 或者 WEB-INF/lib目录下的文件有改动, 即可自动重新加载(reload)项目,在项目开发阶段会特别有用。
为此tomcat设计了自己的类加载机制,顶层的抽象接口是Loader
接口。
顶层设计-Loader接口
1 |
|
Loader接口中通过getClassLoader来获取到自定义的类加载器,同时定义了其它一些方法,具体方法的作用如下:
getClassLoader
方法可以获取到自定义的类加载器,获取到的类加载器是WebappClassLoaderBase
的子类
getContext
和setContext
用来将Loader
关联到Context
上,Context
代表了一个项目(或者说应用),其标准实现类是StandardContext
,因此不同的项目有不同的Loader
,从而实现了项目于项目之间源码的隔离。
getDelegate
和setDelegate
用来设置启用/关闭标准的双亲委派机制,设置为true则不再使用自定义的类加载器,而是使用系统默认AppClassLoader。
getReloadable
和setReloadable
用来设置启用/关闭reloadable, 如果启用reloadable则会通过backgroundProcess启动的后台线程自动监测项目WEB-INF/classes和WEB-INF/lib目录下文件的变动,如果发生变动,会自动reload项目。
modified
方法则用来配合reloadable,发生变动才会reload。
自定义类加载器-WebappClassLoader
具体的类加载任务是由WebappClassLoader
来做的,这个类的父类是WebappClassLoaderBase
,核心的代码是在父类中的,加载类的入口方法是loadClass,加载的具体的流程如下:
- 查找本地缓存,如果在缓存中找到了已经加载过的类则直接返回
- 查找系统ClassLoader的内部缓存,如果加载过直接返回
- 使用ExtClassLoader加载类
- 调用findClass方法加载类,findClass是WebappClassLoaderBase中自定义的方法,一般是去war包下的路径中查找类
- 如果仍然找不到,委托给WebappClassLoader的parent去查找,这里的parent一般为URLClassLoader
需要注意的是第3步到第4步绕过了AppClassLoader,即破坏了默认的双亲委派机制。
具体的代码摘录如下,删除冗余部分
1 |
|