[JVM] (2) In-depth understanding of Java class loading mechanism and parental delegation model


foreword

In Java, the class loading mechanism is an important part of the Java Virtual Machine (JVM), which is responsible for loading Java classes into memory at runtime and converting them into executable code. Understanding the class loading mechanism is crucial to a deep understanding of Java's operating mechanism and the development of high-quality Java applications.

This article provides an in-depth look at Java's classloading process and the parental delegation model. First, I'll detail the five phases of the classloading process. Next, we will focus on the parental delegation model and the problems it solves.

1. Class loading process

1.1 Loading

Loading is the first phase of class loading. At this stage, the JVM will find the corresponding bytecode file according to the fully qualified name of the class and load it into memory . The loading phase not only includes reading bytecode from the file system, but may also include loading class bytecode from the network, database, etc.

In detail, the loading phase of the class needs to complete three tasks:

  1. Obtain byte stream :
    The Java virtual machine obtains the binary byte stream that defines the class according to the fully qualified name (Fully Qualified Name) of the class. This process can read the bytecode file of the class from the local file system, network, JAR package, etc., and store it in memory.

  2. Convert to runtime data structure :
    After obtaining the byte stream of the class, the Java virtual machine converts the static storage structure represented by the byte stream (such as classes, fields, methods, constant pools, etc.) into runtime data in the method area structure. This process includes parsing various information in the bytecode and generating corresponding runtime data structures for performing various operations of the class at runtime.

  3. Generate java.lang.Class object :
    Generate an object representing this class in memory java.lang.Class. This Classobject is an object that represents the metadata information of a class in the JVM. Through this object, information such as methods, fields, and constructors of the class can be accessed, and various operations of the class can be performed. This Classobject is also the entry point to obtain the class in the Java program, through which various static and dynamic information of the class can be accessed.

Note :“加载”(Loading)阶段是整个“类加载”(Class Loading)过程中的一个阶段,它和类加载 (Class Loading) 是不同的,一个是加载 (Loading)另一个是类加载 (Class Loading),不要把二者混淆。

1.2 Verification

Validation is the second stage of the class loading process. In the verification phase, the JVM will verify the loaded bytecode to ensure that the structure of the bytecode is legal and conforms to the specification, and does not contain security holes and content that does not conform to the JVM specification. This phase is an important step in ensuring the security and correctness of the class loading process .

The following figure is the structure definition of the Class file in the Java Virtual Machine Specification, which is also required for verification in the verification phase:

1.3 Preparation

Preparation is the third phase of the class loading process. During the preparation phase, the JVM allocates memory for the static variables of the class and sets initial values ​​(usually zero values) . The operation of assigning values ​​to static variables is not included here, and the operation of assigning values ​​will be performed in the initialization phase .

For example, there is such a piece of code:

public static int value = 100;

In the preparation phase, the JVM will allocate memory for the static variable value, but the initial value of the setting is 0not 100, because the assignment operation is done in the initialization phase.

1.4 Analysis

Resolution is the fourth phase of the class loading process. During the resolution phase, the JVM replaces symbolic references with direct references .

  • A symbolic reference is a reference generated at compile time to describe classes, fields, methods, etc.
  • A direct reference is a reference that points directly to an address in memory .

The purpose of the parsing phase is to resolve symbolic references into direct references, so that the referenced target can be located more quickly in subsequent program execution .

1.5 Initialization

Initialization is the final stage of the class loading process. In the initialization phase, the JVM will execute the initialization code of the class, including pairing 静态变量赋值and执行静态初始化块 . The initialization of the class is triggered when the class is used for the first time. Only after the initialization is complete, the class is actually loaded and ready.

2. Parental delegation model

2.1 Class loader

When you mention the class loading mechanism of the JVM, you can't help but think of it 双亲委派模型. To understand this model, you first need to understand the class loader.

In the JVM, there are three class loaders by default:

  1. 启动类加载器(Bootstrap Class Loader)

    • This is a special class loader implemented inside the JVM, written in C++, not a Java class ;
    • It is responsible for loading the classes needed by the JVM itself , including core class libraries (such as java.langclasses in packages), etc.;
    • The startup class loader is the topmost level of the class loader hierarchy and has no parent loader ;
    • Since it is written in C++, it cannot be directly referenced in Java code.
  2. 扩展类加载器(Extension Class Loader)

  • Extension class loaders are Java classes sun.misc.Launcher$ExtClassLoaderimplemented by;
  • It is responsible for loading lib/extthe classes in the extension directory of JRE (Java Runtime Environment) ;
  • 扩展类加载器yes ; 启动类加载器_子加载器
  • It is also an intermediate layer in the class loader hierarchy.
  1. 应用程序类加载器(Application Class Loader)
  • Application class loaders are also Java classes, sun.misc.Launcher$AppClassLoaderimplemented by;
  • It is responsible for loading the classes under the applicationclasspath我们自己编写的 Java 类 , namely ;
  • 应用程序类加载器yes ; 扩展类加载器_子加载器
  • Also at the bottom of the classloader hierarchy.

The above three class loaders construct the class loader hierarchy of the JVM, ie 双亲委派模型. In addition to 启动类加载器being implemented by the C++ language, all other loaders are implemented by Java and are inherited java.lang.ClassLoader.

The following figure shows the JVM's class loader hierarchy:

Of course, in addition to the default three class loaders, developers can also implement custom class loaders according to their own needs. Custom class loaders need to inherit from and implement specific class loading logic java.lang.ClassLoaderby overriding methods. findClassCustom class loaders are often used to implement functions such as plug-in mechanism and hot deployment.

2.2 What is the parent delegation model

The parental delegation model is a class loading mechanism of the Java class loader. Simply put, the core idea is: when a class loader receives a class loading request, it will not try to load the class itself first, but delegate the request Leave it to the parent classloader to do it.

The class loading process of the parent delegation model is roughly shown in the following figure:

  • When a class loader receives a loading request (child loader), it first delegates the loading request to its parent loader , and the parent loader may continue to delegate to its parent loader, recursively.
  • Classloading is not attempted until the topmost level of the classloader hierarchy (the startup classloader) is reached.
  • If the current loader cannot load, it will hand over the loading task to its sub-loader, and the sub-loader will try to load the class .

2.3 Problems solved by the parental delegation model

The parental delegation model mainly solves two problems:

  1. Class isolation and conflict prevention
  • In a complex Java application, many different class libraries and modules may be involved. These class libraries and modules may refer to the same class name, which may lead to class name conflicts if not restricted .
  • The parent delegation model ensures that each class loader delegates the loading task to the parent loader through the class loader of the hierarchical structure, so that the class with the same name will only be loaded once, and the loading process is orderly, avoiding Class conflict and confusion .

for example:

  • Suppose the application's class loader needs to load java.lang.Stringthe class.
  • It will first delegate to the extension class loader, which cannot be found, and then delegate to the startup class loader. Since the startup class loader was able to find and load java.lang.Stringthe class, it returns the class to the application class loader.
  • Due to the delegation order of the class loader, even if 自定义there are java.lang.Stringclasses in the application, they will not be loaded, thus ensuring class isolation and preventing conflicts.
  1. Security and Trusted Code Execution

The core class libraries in Java reside inside the JVM, and they provide the basic functionality of the Java programming language. These core class libraries are loaded by the startup class loader when the JVM starts. With the parent delegation model, yes确保核心类库只会被启动类加载器加载,而不会被应用程序类加载器或其他自定义类加载器加载 .

这种安排提高了Java程序的安全性,因为核心类库的来源可信,不会被恶意类替代. If the application class loader is allowed to directly load the core class library, malicious classes may replace some classes in the core class library, resulting in a security hole. The parental delegation model ensures the execution of trusted code and prevents tampering of malicious classes by limiting the loading of core class libraries .

2.4 Breaking the Parental Delegation Model

Although the parental delegation model is beneficial in most cases, there are specific scenarios where it needs to be broken , of which JDBCis a typical example :

  • In JDBC, database vendors provide their own JDBC drivers, these drivers实现了 JDBC 标准接口的类库 . Because JDBC drivers need to interact with specific databases, they are usually provided by database vendors rather than part of the Java standard. There are many database vendors, so there are many types of JDBC drivers.

  • Considering this situation, the JDBC driver needs to be loaded by the application itself, rather than delegated to the parent class. If 双亲委派模型the class loading is still performed according to the rules at this time, then the classes provided by Java are loaded JDBC 标准接口的类库, not the classes of a specific database.

  • In order to solve this problem, the loading of JDBC drivers is usually implemented through reflection , and the application class loader can directly load the driver's class without going through the parent delegation model. In this way, the application can load the specific driver class it needs without being restricted by the parent class loader .

Guess you like

Origin blog.csdn.net/qq_61635026/article/details/132048490