定义:
在Java的标准类加载机制中,采用的是双亲委派模型。在这个模型中,
当一个类加载器需要加载一个类时,它首先会委托给其父类加载器尝试加载。如果父类加载器无法加载,才会由当前类加载器自己尝试加载。
tomcat打破双亲委派
在Servlet容器(如Tomcat)中,每个Web应用程序都有自己的类加载器结构,以实现类的隔离。这是因为不同的Web应用程序可能会包含相同的库或类,而这些类可能有不同的版本或者具有特定的应用程序上下文信息。如果按照标准的双亲委派模型,所有Web应用程序都将共享同一个系统类加载器,这将导致类冲突或不正确的类加载。
因此,Tomcat设计了自己的类加载器架构,通常包括以下三个主要的类加载器:
1,Bootstrap ClassLoader:负责加载Java的核心库,遵循标准的双亲委派模型。
2,System ClassLoader:负责加载Tomcat自身的库和类,也遵循标准的双亲委派模型。
3,Web Application ClassLoaders:每个Web应用程序都有自己的类加载器,这些类加载器打破了双亲委派模型。它们首先尝试从自己的classpath中加载类,如果找不到,再委托给父类加载器(通常是Common ClassLoader,它是Tomcat的一个共享类加载器,位于System ClassLoader和Web Application ClassLoaders之间)。
有什么好处
通过这种打破双亲委派模型的方式,Tomcat能够为每个Web应用程序提供独立的类加载环境,确保不同应用程序之间的类隔离,同时也能灵活地处理Servlet和JSP的动态加载和更新。这种方式虽然增加了复杂性,但也更好地满足了Web应用程序部署和运行的需求。
---------------------------------下面是一些概念有兴趣的了解-------------------------------------
Java类加载机制
Java的类加载机制是Java虚拟机(JVM)中的核心部分之一,它负责将Java源代码编译为字节码文件,并将其转换为可以由JVM执行的类。Java的类加载机制遵循双亲委派模型(Parent Delegation Model)。
具体的来说是指将类的**.class字节码文件读入到内存中,并在运行时数据区中的方法区保留类的数据结构,同时在堆中创建一个与之对应的Class对象**,该过程主要经历以下几个阶段:
参考图1:jvm内存模型
参考图2:类加载过程
加载(Loading):通过一个类的全限定名找到其对应的.class字节码文件,将其中的二进制数据读取到方法区。
验证(Verification):对字节码文件进行文件格式验证、元数据验证、字节码验证、符号引用验证等,确保其符合Java虚拟机规范,不会危害JVM。
准备(Preparation):给类中的静态字段信息分配内存空间,并设置初始值。这个阶段中,内存分配只包括static修饰过的静态变量,实例变量等到对象实例化时才会分配内存。初始值是变量类型的默认值,而不是在Java代码中显示赋予的值。
解析(Resolution):把.class字节码文件中常量池内的符号引用转换为直接引用。这个阶段可以理解为当前加载的这个类和它所引用的类正式建立连接的过程。
初始化(Initialization):在初始化阶段,类的静态初始化器和初始化块会被执行,对类的静态变量和静态方法进行初始化。需要注意的是,在初始化阶段之前,类的加载过程需要按照一定顺序完成。具体来说,加载、验证、准备、解析四个阶段需要在初始化阶段之前全部完成。这是因为初始化阶段需要使用到在加载和解析阶段中验证过的字节码文件和符号引用,所以需要在这些阶段完成后才能进行初始化。
Java的类加载器
Java的类加载器主要分为三类:启动类加载器、扩展类加载器和应用程序类加载器。不同的类加载器负责加载不同的类,在Java的类加载机制中,具有不同级别的权限和不同的类搜索路径。
双亲委派机制
双亲委派机制是Java虚拟机在加载类时采用的一种机制;
当一个类加载器收到了类加载的请求时,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则会进一步向上委托,依次递归请求,最终请求将到达顶层的启动类加载器。如果父类加载器可以完成类加载任务,就成功返回,如果父类加载器无法完成此加载任务,子加载器才会尝试自己去加载。
双亲委派机制是为了避免类的重复加载和JVM的安全性。通过这种机制,可以确保每个类都被一个唯一的类加载器加载,并且不会出现多个类加载器同时加载同一个类的情况。同时,由于JVM中的核心类库(例如java.lang、java.util等)都是由启动类加载器负责加载的,因此这些核心类库的类会被所有的Java应用程序共享,从而确保了安全性。
双亲委派机制在Java虚拟机中的实现主要依赖于ClassLoader类和它的子类。ClassLoader类是所有类加载器的基类,它提供了委托加载机制的实现。当一个类加载器需要加载一个类时,它会首先调用其父类加载器的loadClass()方法,如果父类加载器无法加载该类,则再调用其自身的loadClass()方法尝试加载。如果一个类已经被父类加载器加载过,则直接返回已经加载的类对象;否则,调用findClass()方法尝试自己加载该类。
双亲委派机制在Java虚拟机中默认是开启的,但是可以通过设置JVM参数来关闭它。如果关闭了双亲委派机制,虽然可以允许自定义类加载器的开发,但也可能会带来一些安全和性能方面的问题。因此,在大多数情况下,建议保持默认开启双亲委派机制。