美文网首页
java 类加载器&双亲委派机制

java 类加载器&双亲委派机制

作者: 追风还是少年 | 来源:发表于2023-09-05 08:47 被阅读0次

类加载器(ClassLoader)

class文件在jvm经过加载、链接、初始化三个步骤,链接分为验证、准备、解析三个步骤
只有加载是程序员能控制的,其它几个步骤都是由jvm自动运行的。

触发class文件加载的时机:
1、当创建类的实例,例如:使用new关键字、通过反射、克隆、反序列化
2、当调用类的静态方法
3、当使用类或接口的静态字段(final常量除外)
4、当初始化子类,要求先初始化父类
5、作为启动虚拟机,含有main方法的那个类

java.lang.ClassLoader:
1、public Class<?> loadClass(String name) throws ClassNotFoundException
给定一个类名,加载一个类,返回代表这个类的 Class 实例,如果找不到类,则返回异常。

2、protected final Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError
根据给定的字节码流 b 定义一个类,off 表示位置,len 表示长度。该方法只能被子类使用,不能被覆盖修改。

3、protected Class<?> findClass(String name) throws ClassNotFoundException
查找一个类,这是重载 ClassLoader 时,最重要的系统扩展点。这个方法会被 loadClass 调用,用于自定义查找类的逻辑,如果不需要修改类加载默认机制,只是想改变类加载的形式,就可以重载该方法。

4、protected final Class<?> findLoadedClass(String name)
去寻找已经加载的类,该方法只能被子类使用,不能被覆盖修改。

ClassLoader有哪些:
1、Bootstrap ClassLoader(启动类加载器),负责加载 <JAVA_HOME>/lib 目录中的,或者别-Xbootclasspath 参数指定的路径。并且是被虚拟机识别的,如 rt.jar,名字不符合的类库即使放在 lib 目录中也不会加载
2、Extension ClassLoader(扩展类加载器),由sun.misc.Launcher$ExtClassLoader 实现,负责加载 <JAVA_HOME>/lib/ext 目录中的。或者被 java.ext.dirs 系统变量所指定的路径中的所有类库
3、Aplication ClassLoader(应用类加载器),由sun.misc.Launcher$AppClassLoader 实现,由于这个类是 ClassLoader 中的 getSystemClassLoader 方法的返回值,也称为系统类加载器,负载加载用户类路径(ClassPath)上所指定的类库,开发者可以直接使用这个类加载器。一般情况下,这个就是程序中默认的类加载器

双亲委派机制

双亲委派机制的工作过程是:如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把这个请求委派父类加载器去完成。每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个请求(他的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。

双亲委派模型固然有着优点,能够让整个系统保持了类的唯一性。但在有些场合,却不适合,也就是说,顶层的启动类加载器的代码无法访问到底层的类加载器。如 rt.jar 中代码无法访问到应用类加载器
在 Java 平台中,把核心类(rt.jar)中提供外部服务,可由应用层自行实现的接口,通常可以称为 Service Provider Interface,即 SPI, jdk内置的spi实现为ServiceLoader
在 rt.jar 中的抽象类需要加载继承他们的在应用层的子类实现,但是以目前的双亲委派模型是无法实现的。
因此 JDK 引用了一个不太优雅的设计,上下文类加载器。也就是将类加载放在线程上下文变量中。通过 Thread.getContextClassLoader(), Thread.setContextClassLoader(ClassLoader) 这两个方法获取和设置 ClassLoader,这样,rt.jar 中的代码就可以获取到底层的类加载了
双亲模式是虚拟机的默认行为,但并非必须这么做,通过重载 ClassLoader 可以修改该行为。事实上,很多框架和软件都修改了,比如 Tomcat,OSGI。具体实现则是通过重写 loadClass 方法,改变类的加载次序。比如先使用自定义类加载器加载,如果加载不到,则交给双亲加载
由不同的 ClassLoader 加载的同名类属于不同的类型,不能相互转化和兼容。
而这个特性就是我们实现热替换的关键

破坏双亲委派机制

  • 基础类调用会用户的代码
    JNDI现在已经是Java的标准服务,它的代码由启动类加载器去加载(在JDK1.3时就放进去的rt.jar),但它需要调用由独立厂商实现并部署在应用程序的ClassPath下的JNDI接口提供者(SPI, Service Provider Interface)的代码,但启动类加载器不可能“认识“这些代码啊。因为这些类不在rt.jar中,但是启动类加载器又需要加载。

  • 为了实现热插拔,热部署,模块化,意思是添加一个功能或减去一个功能不用重启,只需要把这模块连同类加载器一起换掉就实现了代码的热替换,如:OSGI

  • Tomcat

Tomcat的类加载机制

  • 隔离,不同web应用依赖的相同类库不同版本
    一个web容器可能需要部署两个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离。
  • 共享,不同web应用依赖的相同类库相同版本
    部署在同一个web容器中相同的类库相同的版本可以共享。否则,如果服务器有10个应用程序,那么要有10份相同的类库加载进虚拟机,这是扯淡的。
  • 隔离,web容器依赖类库和web应用依赖的类库
    web容器也有自己依赖的类库,不能与应用程序的类库混淆。基于安全考虑,应该让容器的类库和程序的类库隔离开来。
  • jsp动态修改
    web容器要支持jsp的修改,我们知道,jsp 文件最终也是要编译成class文件才能在虚拟机中运行,但程序运行后修改jsp已经是司空见惯的事情,否则要你何用? 所以,web容器需要支持 jsp 修改后不用重启。
image.png

Tomcat自己定义的类加载器:

  • CommonClassLoader
    加载/common/*中的类库。
    Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问。
  • CatalinaClassLoader
    加载/server/*中的类库。
    Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见。
  • SharedClassLoader
    加载/shared/*中的类库(在tomcat 6之后已经合并到根目录下的lib目录下)。
    各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见。
  • WebappClassLoader
    加载/WebApp/WEB-INF/*中的类库。
    各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见。

CommonClassLoader能加载的类都可以被Catalina ClassLoader和SharedClassLoader使用,从而实现了公有类库的共用,而CatalinaClassLoader和Shared ClassLoader自己能加载的类则与对方相互隔离。

WebAppClassLoader可以使用SharedClassLoader加载到的类,但各个WebAppClassLoader实例之间相互隔离。

而JasperLoader的加载范围仅仅是这个JSP文件所编译出来的那一个.Class文件,它出现的目的就是为了被丢弃:当Web容器检测到JSP文件被修改时,会替换掉目前的JasperLoader的实例,并通过再建立一个新的Jsp类加载器来实现JSP文件的HotSwap功能。

tomcat 为了实现隔离性,没有遵守双亲委派机制,每个webappClassLoader加载自己的目录下的class文件,不会传递给父类加载器。

相关文章

  • 从类加载开始的JVM学习

    目录 引言 java类加载流程 java类加载机制- 类加载原理- 双亲委派机制 Tomcat中双亲委派机制的应用...

  • 为什么使用双亲委派机制?

    为什么使用双亲委派机制? 专业名词 说双亲委派机制就不得不说类加载器。 引导类加载器:加载%JAVA_HOME%/...

  • 简单了解什么是双亲委派机制?

    什么是双亲委派机制 了解双亲委派,需要先了解下JAVA的类加载器ClassLoader,java的类加载器主要有以...

  • JAVA类加载机制

    jvm之java类加载机制和类加载器(ClassLoader)的详解java类加载机制:全盘负责、双亲委派、缓存机...

  • 四、初识ClassLoader

    双亲委派的定义 类加载器的父亲委托机制(双亲委派机制) 类加载器加载一个类时,会优先交给其父的加载器加载,父加载器...

  • JVM系列(九):Java类加载机制之双亲委派模型

    前言 双亲委派模型是Java加载类的机制.采用双亲委派模型的好处是Java类随着它的类加载器一起具备了一种带有优先...

  • 3.手写自己的java类加载器

    类的加载过程?何为双亲委派机制?为啥这么设计?实现一个自己的类加载器?如何打破双亲委派机制? 1.类加载器 jar...

  • Java虚拟机

    JVM 组成部分 类加载器 执行引擎 内存区 本地方法调用 类加载器 双亲委派模型 类的加载过程采用双亲委派机制,...

  • 为何采用双亲委派机制

    一、双亲(父亲)委派机制 java中存在3种类型的类加载器:引导类加载器,扩展类加载器和系统类加载器。三者是的关系...

  • java类加载破坏双亲委派模型

    前面java类加载器与双亲委派模型中提到Java采用个双亲委派的方式来完成类加载,但是双亲委派模型并不是一个强制的...

网友评论

      本文标题:java 类加载器&双亲委派机制

      本文链接:https://www.haomeiwen.com/subject/vgvyuctx.html