聊一聊java的类加载机制

文摘   2024-12-25 08:23   福建  

Java的类加载机制是Java虚拟机(JVM)的一个重要特性,确保了Java应用程序能够运行在不同的环境下。类加载机制主要负责以下三个主要任务:

  1. 加载:查找并加载类的二进制数据。
  2. 连接:
  • 验证:确保加载的类的正确性。
  • 准备:为类变量分配内存,并设置类变量的默认初始值。
  • 解析:将类中的符号引用转换为直接引用。
  • 初始化:对类进行初始化,包括静态变量的赋值和静态代码块的执行。
  • 类加载机制涉及以下几个关键概念:

    • 类加载器(ClassLoader):JVM通过类加载器来加载类。在Java中,类加载器是一个能够将类加载到JVM中的对象,它主要分为以下四种:

      • 引导(Bootstrap)类加载器:这是虚拟机自带的类加载器,负责加载Java的核心库(如rt.jar中的类),无法直接获取。
      • 扩展(Extension)类加载器:这是加载Java平台扩展功能的类加载器,它负责加载$JAVA_HOME/lib/ext目录中或由系统属性java.ext.dirs指定位置中的类库。
      • 应用程序(Application)类加载器:这是类ClassLoader的系统默认实现,负责加载应用程序classpath上的类库。
      • 用户自定义(User-Defined)类加载器:开发者可以通过继承ClassLoader类来创建自己的类加载器,以实现特定需求。
    • 双亲委派模型(Parent Delegation Model):当一个类加载器收到类加载的请求时,它不会首先尝试自己去加载这个类,而是把请求代理给它的父类加载器去执行。如果父加载器不能完成这个加载(例如,因为它不认识这个类),子加载器才会尝试自己去加载这个类。

    这种模型的优势在于Java类总是被某个被信任的类加载器所加载,这保证了Java应用运行时的安全性。同时也避免了类的多次加载,由于在JVM内存中,同一个类可以被加载多次,如果使用不同的类加载器的话,那么这些类虽然来源相同但会被认为是不同的类。

    Tomcat类加载机制

    Tomcat 作为一个 Servlet 容器,实现了 Java EE 的 servlet 规范,并提供了自己的类加载器结构,用于加载和管理不同 Web 应用程序的类和资源。Tomcat 的类加载器结构能够实现对每个 Web 应用程序的隔离,这意味着它确实“打破”了标准的 Java 类加载机制中的双亲委派模型,至少是相对于 Java EE Web 应用的上下文环境而言的。

    Tomcat的类加载器架构主要由以下几个层次组成:

    1. Bootstrap ClassLoader:最顶层的类加载器,负责加载 JVM 自身的类库,如 rt.jar 包中的类,这是 JVM 的一部分。

    2. System ClassLoader:加载系统类路径(CLASSPATH)中的类,通常加载的是你的应用程序的类。

    3. Common ClassLoader:加载Tomcat的lib目录下的 JAR 文件和类。它们对所有的 Web 应用程序都是可见的。

    4. Catalina ClassLoader(可选):负责加载Tomcat服务器自身的类,通常不涉及 Web 应用程序。

    5. Shared ClassLoader(可选):如果配置正确,它可以用来加载多个 Web 应用程序所共享的类和资源,通常是存放在 ${catalina.base}/shared 目录下。

    6. Webapp ClassLoader:每个 Web 应用都有自己的类加载器实例,它加载位于 /WEB-INF/classes 和 /WEB-INF/lib 下的类和 JAR 文件。这些类对于其他 Web 应用不可见,确保了 Web 应用之间的隔离性。

    正是由于 Tomcat 提供了 Webapp ClassLoader,它允许每个应用使用自己的类路径,并存放自己的库文件,使得相同的 Java 类可以存在于不同的 Web 应用中,而互不干扰。这一点区别于传统 Java 应用,其中的类加载器通常遵循双亲委派模型,最终会沿着类加载器的层级树向上查找,直至 Bootstrap ClassLoader。

    Tomcat 打破双亲委派模型的关键在于 Webapp ClassLoader 的行为。在标凈的双亲委派模型中,类加载器首先会委派到父加载器去尝试加载一个类,只有在父加载器加载失败时才会尝试自己加载。但是为了实现 Web 应用的隔离,Tomcat 的 Webapp ClassLoader 在尝试委派给父加载器之前,首先会尝试自己加载这个类。这种自下而上的加载行为违反了标准的双亲委派模型。

    这种机制有助于防止应用之间共享类库或者彼此影响,从而在 Tomcat 这样的容器中实现多个应用稳定和安全地并行运行。不过,如果开发者不希望打破双亲委派模型,也可以通过配置使得 Tomcat 中的 Web 应用遵循标准 Java 类加载器的行为。

    程序员技术成长之路
    技术简介:涉及多个编程语言go、php、java。曾任职于互联网大厂,有多年开发编程经验。欢迎互相交流