1.什么是双亲委派
jvm启动后会通过其类装载子系统,去硬盘上找xxx.class文件,找到之后,会直接将xxx这个类装载到java虚拟机中,这个过程叫做类的加载。而类的加载过程中就涉及到了双亲委派。
类加载机制的双亲委派(Parent Delegation Model)是Java中的一种类加载策略,旨在确保Java应用程序的安全性和一致性。其基本原理如下:
-
加载顺序:当一个类加载器接到加载某个类的请求时,它首先会将该请求委派给它的父类加载器。如果父类加载器能够加载这个类,则请求返回给调用者;如果父类加载器无法加载该类,加载请求才会被当前类加载器处理。
-
层级结构:Java的类加载器通常以树形结构组织,顶层是引导类加载器(Bootstrap ClassLoader),接下来是扩展类加载器(Extension ClassLoader)和应用类加载器(Application ClassLoader)。每个加载器都有自己的父加载器。
-
避免重复加载:通过这种机制,Java避免了同一个类被多个类加载器加载的情况,从而防止类的冲突和版本不一致的问题。例如,如果系统中有两个不同版本的同一类,双亲委派机制确保只有一个版本会被加载,避免了潜在的错误和不兼容。
-
安全性:双亲委派机制也增强了Java的安全性,因为它优先加载Java核心类库中的类,而不是用户自定义的类。这意味着用户无法轻易地替换系统核心的类,防止了潜在的安全漏洞。
双亲委派整体流程如下图:
2.Tomcat为什么需要打破双亲委派呢
首先需要明确,在jvm中一个class对象是否唯一,主要依赖于类加载器和类的全限定名,如果二者均一样,那么说明两个class对象一样。
那么问题来了,tomcat是一个servlet容器,再该容器下我们可以部署多个项目,如果仅依赖于全局的类加载机制(双亲委派机制),那么如果我们在该容器下部署了两个项目,项目中均存在一个全限定名为com.controller.HelloWord的类,但是该类的方法和属性完全不同。如果按照双亲委派机制使用全局的Application ClassLoader来加载该类,那么该类因为类加载器和全限定名一致,所以只会被加载一次,这样就会存在问题。所以Tomcat通过自定义加载器的方式打破了双亲委派机制。
注意:所谓的打破并不是完全不遵守双亲委派机制,Tomcat通过为每个context(项目)定义自己的WebAppClassLoader,加载项目内的class对象,对于一些公共的,比如jdk提供的数据类型等还是要走双亲委派机制。
3.Tomcat的类加载机制
Tomcat的启动加载跟普通项目一样,因为其本身就是一个Java项目,有自己的main方法启动类,但是Tomcat在jvm的基础上自定义了很多类加载器,其整体工作流程如下:
上面的橙色部门还是和原来一样, 采用双亲委派机制。 而黄色部分是Tomcat第一部分自定义的类加载器,这部分主要是加载Tomcat包中的类,这一部分依然采用的是双亲委派机制,而绿色部分是Tomcat第二部分自定义类加载器,正是这一部分,打破了类的双亲委派机制。下面我们就来详细看看Tomcat自定的类加载器:
-
commonClassLoader: tomcat最基本的类加载器, 加载路径中的class可以被tomcat容器本身和各个webapp访问,如Servlet规范相关包和一些通用工具包;
-
catalinaClassLoader: tomcat容器中私有的类加载器, 加载路径中的class对于webapp不可见。
-
sharedClassLoader: 各个webapps共享的类加载器, 加载路径中的class对于所有的webapp都可见, 但是对于tomcat容器不可见。
-
WebappClassLoader:各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见;每一个应用会创建一个该对象实例进行加载 其加载目录为每个应用的WEB-INF/class以及lib。
注意:再高版本的Tomcat中,黄色部分进行了合并(默认情况下三个加载器使用了同一个,但是通过配置仍可以恢复成三个不一样的类加载器),合并后的工作流程如下:
4.从源码层面探究Tomcat的类加载机制
Tomcat也是一个Java项目,其启动时也是执行Bootstrap中的main方法,如下图:
接下来我们就详细的看一下initClassLoaders(),是如何初始化类加载器以及他们的关系:
深入源代码,探秘Tomcat类加载机制:为何颠覆双亲委派原则(2)?-CSDN博客
标签:委派,Tomcat,双亲,机制,源代码,探秘,class,加载 From: https://blog.csdn.net/qq_26733517/article/details/144187816