Java类加载过程
2024-06-17 19:46:49

Java类加载过程

Java中类的加载过程如下图:

类加载过程

其中连接过程又分三步:验证–>准备–>解析

  • 加载:
    • 通过一个类的完全限定查找此类字节码文件,并利用字节码文件创建一个 Class 文件
  • 验证:
    • 确保 Class 文件字节流中包含的信息符合当前虚拟机要求,不会危害虚拟机安全。主要包括文件格式验证元数据验证字节码验证符号引用验证
  • 准备:
    • 类变量分配内存并赋初值,此处不包括 final 修饰的变量
  • 解析:
    • 主要将常量池中的符号引用转变为直接引用
  • 初始化:
    • 若该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化变量。

双亲委派模型

三层类加载器

  • 启动类加载器 BootStrap ClassLoader:负责加载存放在 \lib 目录或被 -Xbootclaspath 参数,启动类加载器无法被 Java 程序直接引用,用户在自定义类加载器时,需要给引导类加载器处理
  • 扩展类加载器 Extension Classloader:负责加载 \lib\ext 目录或者被 java.ext.dirs 系统变量所指定的目录中的所有类库
  • 应用程序类加载器 Application Classloader(也叫系统类加载器):负责加载用户类路径 ClassPath 上的所有类库

两个 class 对象是否是同一个类对象

  • 类的全限定名,包括包名必须一致
  • 加载这个类的 ClassLoader 必须相同,即 ClassLoader 实例对象

双亲委派模型加载过程

  1. 如果一个类加载器收到类加载请求,它首先不会自己尝试加载这个类,而是把请求委托到父类执行。
  2. 每一层次的类加载器都会委托其父类加载器去完成,最终传回最顶层的启动类加载器中。
  3. 只有当所有父类加载器都无法完成这个类的加载请求时,子类加载器才会进行加载

作用

  • 这样可以避免重复加载类,当父类已经加载了该类时,就没必要再加载一次
  • 考虑到安全因素,双亲委派模型可以避免子类加载器加载已经被父类加载器加载过的类。

破坏双亲委派模型

为什么要破坏双亲委派模型?

  • 因为类加载器受到加载范围的限制,在某些情况下父类加载器无法加载到需要的文件,这是就需要打破双亲委派模型,委托子类加载器去加载 Class 文件

怎么打破双亲委派模型

  • 使用线程上下文类加载器(ContextClassLoader)加载类,一般 ContexClassLoader 默认为应用类加载器

打破实例:

  • JDBC 各种驱动的实现

    • 加载 Driver 接口实现类的时候,DriverManager 由启动类加载器加载,而实现类由服务提供商加载

    image-20220317012236388

  • Tomcat

    • 各个 webapps 需要隔离的环境,也需要一些共享的类
    • Tomcat 使用自定义类加载器去加载类,以免恶意或无意破坏
    • 热部署