前言
主流的 Java web 服务器 (Tomcat,Jetty,WebLogic,WebSphere 等) 都有多个自定义的类加载器以及具备的类加载优势, 本篇博文主要是通过以 Tomcat 为例简单认识 Java Web 服务器具有的特点, 以及自定义类加载器是如何实现的. 此外, 本篇博文主要是根据 Tomcat 5.x 类加载架构编写的.
主要参考资料深入理解 Java 虚拟机
1,Web 服务器需要解决的问题
一个功能健全的 Web 服务器, 都需要解决如下几个问题:
(1)
同一个服务器上的两个 Web 程序所使用的 Java 类库实现相互独立隔离
: 不能一个类库在同一个服务器上只有一份却被多个程序使用.
(2)
同一个服务器上的两个 Web 应用程序所使用的 Java 类库可以被共享
: 如果不能共享的话, 虚拟机内部的 Method Area 可能会出现过度膨胀现象.
(3)
服务器的类库要与 Web 应用程序的类库相互隔离, 互不影响(即服务器不收 Web
程序的影响): 很多服务器可能是用 Java 来实现, 自然就得使用一些只属于自己的类库.
(4)
支持 JSP 的热替换(HotSwap)
: 大部分主流服务器 (WebLogic 除外) 修改 JSP 文件都不需要重启服务器.
试想一下, 如果上述的 4 点中任何一点不能满足, 特别是 (1)-(3) 点, 那么整个 Java Web 服务器都是 "混乱" 的, 或者说是不健全的.
2,Tomcat 类库存放目录
既然要满足以上四点基本要求, 那么当部署一个 Web 应用时, 一个 Classpath 路径目录是无法满足需求的, 通常会提供多个 Classpath(一般以 classes/lib 命名)路径目录, 而目录中都会有一个相应的自定义类加载器去加载里面的 Java 类. 在 Tomcat 中就有三组目录, 分别是:/common/*,/server/*,/shared/*;
但值得强调的是在 Tomcat 6.x 之后这三组目录就不存在了, 只有一个总的 / lib 目录, 其他都需要进入配置文件需要时单独配置. 所以这里介绍的目录未必能在 tomcat 安装目录下找到, 不过其用意都是一样的;
(1)
/common/*: 实际创建的时候为 / common/lib / 目录, 可以被 Tomcat 与所有的 Web
应用共享的类库都在里面;
但是在 Tomcat 6 之后 / common/lib / 目录被废弃, 现在默认的是在 / lib / 下, 实际上是将 / common,/server,/shared 三个目录默认合并到一个 / lib 目录下. 如果不满足具体的业务需求的话, 可以在 conf/catalina.properties 中设置 server.loader 与 shared.loader. 打开 conf/catalina.properties 可以看到: 无论是 ${catalina.base}, 还是 "${catalina.home}, 都会去找 / lib / 目录, 指定加载的加载器.
CATALINA_BASE: 是实例配置位置, 也就是一个 tomcat 可以配置多个实例, 实例里面有自己的配置;
CATALINA_HOME: 是 tomcat 安装位置;
common.loader,server.loader,shared.loade: 表示 tomcat 指定自定义的三个加载器.
(2)/server/*: 实际创建的时候为 / server/lib 目录, 只能被 Tomcat 使用的类库.
(3)/shared/*: 实际创建的时候为 / shared/lib 目录, 可以被所有的 Web 应用程序共享使用, 但是对 Tomcat 是不可见的.
(4)/webapps(wtswebapps)/project/WEB-INF/*: 实际为 / WebApp/project/WEB-INF/lib, 是 Project
独享有的类库.
3,Tomcat 自定义加载器
Tomcat 自定义的类加载器主要有: ComnonClassLoader,CatalinaClassLoader,SharedClassLoader 和 WebAppClassLoader 四个类加载器.
(1)ComnonClassLoader: 加载 / common/* 目录下的类, 但是上述可知现在的指定加载都会在 Catalina.properties 中配置.
(2)CatalinaClassLoader: 加载 / server/* 目录下的类, 同理现在在 Catalina.properties 中指定配置.
(3)SharedClassLoader: 加载 / shared/* 目录下的类, 同理现在在 Catalina.properties 中指定配置.
(4)WebAppClassLoader: 加载 / webapps(wtswebapps)/project/WEB-INF/* 目录下项目 lib 中的类.
结合之前三个类加载器 (BootstrapClassLoader,ExtensionClassLoader,ApplicationLoader) 与 Tomcat 自定义的四个加载器组合成的委派关系 (Tomcat 服务器的类加载机构) 如下所示:
(注: 其中 JasperLoader 为 Jsp 类加载器, JSP 文件编译后为 Class 文件, 需要加载)
通过此关系图我们可以得到如下两点:
(1)
CatalinaClassLoader 与 SharedClassLoader 是相互隔离独立的;
(2)WebAppClassLoader 可以使用 SharedClassLoader 加载类, 同理 WebAppClassLoader 可以代替 JspClassLoader 加载类, CommonClassLoader 加载的类可以被 CatalinaClassLoader 与 SharedClassLoader 使用.
同时需要注意还有以下两点:
JspClassLoader 只能加载这个 JSP 文件所编译出 Class 文件, 当 JSP 文件被修改时, 会替换当前 JspClassLoader 实例, 之后会重新建立一个新的
JspClassLoader 实例, 这也就是 HotSwap 的内部实现;
不同的 WebAppClassLoader 是相互隔离的;
对于 Tomcat 6.x 版本, 只有在 conf/catalina.properties 中配置了 shared.loader 与 server.loader 才能使用 SharedClassLoader 与 CatalinaClassLoader 实例, 不然会默认使用 ComnonClassLoader 的实例来代替;
如果默认设置不能满足需要, 则可以通过修指定配置文件中的 shared.loader 与 server.loader, 之后重新启动 Tomcat 5.x 加载器架构.
来源: https://www.cnblogs.com/jian0110/p/9478337.html