主流的Java Web服务器,如Tomcat、Jetty等,都实现了自定义的类加载器(一般都不止一个)。一个功能健全的Web服务器,要解决如下几个问题:

1、部署在同一个服务器上的两个Web应用程序所使用的Java类库可以实现相互隔离。这是最基本的需求,两个不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求一个类库在一个服务器中只有一份,服务器应当保证两个应用程序的类库可以相互独立使用。

2、部署在同一个服务器上的两个Web应用程序所使用的Java类库可以实现相互共享。这个需求也很常见,例如,用户可能有10个使用Spring的应用程序部署在同一台服务器上,如果把10份Spring分别存放在各个应用程序的隔离目录中,将会是很大的资源浪费——这主要倒不是浪费磁盘空间的问题,而是指类库在使用时都要被加载到服务器内存,如果类库不能共享,虚拟机的方法区就会很容易出现过渡膨胀的风险。

3、服务器需要尽可能的保证自身的安全不受部署的Web应用程序影响。目前,许多主流的的Java Web服务器自身也是使用Java语言实现的。因此,服务器本身也有类库依赖问题,一般来说,基于安全考虑,服务器所使用的类库应该与应用程序的类库相互隔离。

4、支持JSP应用的Web服务器,大多数都需要支持热替换功能(HotSwap)。我们知道JSP文件最终要编译成Java Class才能由虚拟机执行,但JSP文件由于其纯文本存储的特性,运行时修改的概率远远大于第三方库或程序自身的Class文件。因此,主流的Web服务器都会支持JSP生成类的热替换,而无需重启服务器。

 

由于上述问题的存在,在部署Web应用时,单独的一个ClassPath就无法满足需求了,所以各种Web服务器都“不约而同”地提供了好几个ClassPath路径供用户存放第三方类库,这些路径一般以“lib”或“classes”命名。被放置在不同路径中的类库,具备不同的访问范围和服务对象,通常,每一个目录都会有一个相应的自定义类加载器去加载放置在里面的Java类库。

接下来,以Tomcat服务器为例,看一看Tomcat具体是如何规划用户类库结构和类加载器的。

在Tomcat的目录结构中,有3组目录(“/common/*”,“/server/*”,“/shared/*”)可以存放Java类库,另外还可以加上Web应用程序自身的目录“/WEB-INF/*”,一共4组,把Java类库放置在这些目录中的含义分别如下:

common:类库可以被Tomcat和所有的Web应用程序共同使用。

server:类库可以被Tomcat使用,对所有的Web应用程序都不可见。

shared:类库可以被所有的Web应用程序共同使用,但对Tomcat不可见。

WEB-INF:类库仅仅可以被当前Web应用程序使用,对Tomcat和其他Web应用程序都不可见。

为了支持这套目录结构,并对目录里面的类库进行加载和隔离,Tomcat自定义了多个类加载器,这些类加载器按照经典的双亲委派模型来实现,其关系如图所示:

 

 tomcat

 

参考:http://www.2cto.com/kf/201608/536691.html