preface

Today we are going to talk about the process of class loading in the JVM. We have written so many classes, but we do not know how to load the class.

The JVM is started by bootstrap Class Loader to create an initial class that is specified by the implementation of the JVM. [From official specification]

One of the components of the JVM is the classloader subsystem, which we’ll talk about in detail today.

Java code execution flowchart

Through this flowchart, you can see how the Java code we wrote is executed, which has to go through the class loader process, we will talk about the knowledge point here.

Class loading subsystem

Class loading system architecture diagram

It doesn’t matter if you can’t read these two pictures right now. FollowbrotherTo look down

Class life cycle

The life cycle of a class includes loading, linking, initializing, using, and unloading. Loading, linking, and initializing belong to the process of class loading, which will be explained in detail below. Use means we use the new object, and unload means the object is garbage collected.

The process of class loading

  • Step 1: Loading

Gets the binary byte stream of the class’s.class file using the class’s fully qualified name (package name + class name)

Transform the static storage structure represented by the binary byte stream into the data structure of the method area runtime

Generate a java.lang.Class object in memory that represents this Class and acts as an access point to the various data of this Class in the method area

Summary: Load binary data into memory – > map it to a structure that the JVM can recognize – > generate a class file in memory.

  • Step 2: Linking link

Linking refers to the process of merging the above created class classes into the Java virtual machine for execution, which can be divided into three stages: validation, preparation, and parsing.

① Verify

Ensure that the byte stream in the class file contains information that meets the requirements of the current VM. Ensure that the loaded class class is correct and does not compromise vm security.

② Prepare for

Allocate memory for static fields in the class and set default initialization values, such as 0 for int. Static fields decorated with final are not set because final is assigned at compile time

③ Resolve

The purpose of the parsing phase is to convert symbolic references in a constant pool into direct references (parsing symbolic references in a constant pool into actual references). If a symbolic reference points to a class that has not been loaded, or to a field or method of a class that has not been loaded, parsing triggers the loading of the class (but not necessarily the linking and initialization of the class).

In fact, parser operations are often performed with the JVM after initialization. A symbolic reference is a set of symbols that describe the referenced object. The literal form of symbolic references is clearly defined in the Class file format of the Java Virtual Machine Specification. A direct reference is a pointer to a target directly, a relative offset, or a handle to the target indirectly.

Parsing actions are for classes, interfaces, fields, class methods, interface methods, method types, and so on. Corresponding to CONSTANT_Class_info, CONSTANT_Fieldref_info, and CONSTANT_Methodref_info in the constant pool.

  • Step 3: Initialization Initialization

Initialization is the process of executing the class’s constructor method init().

This method does not need to be defined and is a combination of statements in static code blocks that the Javac compiler automatically collects for all class variable assignments in a class.

If the class has a parent class, the JVM ensures that init of the parent class is executed first, followed by init of the child class.

Classification of class loaders

  • The first: Bootstrap class/Bootstrap ClassLoader

The class loader is implemented in C/C++ and is nested within the JVM so that Java programs cannot manipulate the class directly.

It is used to load Java core libraries, such as JAVA_HOME/jre/lib/rt.jar, resources.jar, and sun.boot.class.path, to provide the packages required by the JVM.

Does not inherit from java.lang.ClassLoader, which has no parent ClassLoader

It loads extension class loaders and application class loaders and becomes their parent class loaders

For security reasons, start classes only load classes whose package names start with Java, Javax, and Sun

  • Second: Extension ClassLoader: Extension ClassLoader

Java language, implemented by sun.misc.Launcher$ExtClassLoader, we can use Java programs to operate the loader

Derived from java.lang.ClassLoader, the parent ClassLoader is the launcher ClassLoader

Load the class libraries from the system property: java.ext.dirs directory, or from the JDK installation directory: jre/lib/ext. We can put our own package in the directory above, it will automatically load in.

  • Third: Application Classloader: Application Classloader

Java language, implemented by sun.misc.Launcher$AppClassLoader.

Derived from java.lang.ClassLoader, the parent ClassLoader is the launcher ClassLoader

It is responsible for loading libraries in the path specified by the environment variable classpath or the system property java.class.path

It’s the default class loader in the program, and all the classes in our Java program are loaded by it.

We can get and manipulate this loader by using ClassLoader#getSystemClassLoader()

  • Fourth: custom loader

Under normal circumstances, the above three loaders can meet our daily development work, if not, we can also customize the loader

For example, when a Java class is loaded on the network, encryption is used to ensure the security of transmission. Therefore, the above three loaders cannot load the class. In this case, a custom loader is required

Custom loader implementation steps

Inherit the java.lang.classloader class and override the findClass() method

If the requirements are not too complicated, you can inherit the URLClassLoader class directly and override the loadClass method. For details, see AppClassLoader and ExtClassLoader.

There are several ways to get a ClassLoader

It is an abstract class, and all subsequent classloaders inherit from the ClassLoader (excluding the launcher ClassLoader).

// Method 1: Get the ClassLoader of the current class
clazz.getClassLoader()

// Method 2: Get the ClassLoader of the current thread context
Thread.currentThread().getContextClassLoader()

Method 3: Obtain the ClassLoader of the system
ClassLoader.getSystemClassLoader()

// Method 4: Get the caller's ClassLoader
DriverManager.getCallerClassLoader()
Copy the code

Class loading mechanism – parent delegate mechanism

The JVM loads class files on demand, and when the class needs to be used, the JVM loads its class files into memory to produce class objects.

When a class is loaded, it uses the parent delegate mechanism, a task-delegate pattern in which requests are handed over to the parent class.

  • The working principle of

(1) If a classloader receives a classload request, it will delegate the request to the parent classloader rather than load it first.

(2) if the parent class still has a parent ClassLoader, delegate up until the Bootstrap ClassLoader

(3) If the parent class loader can complete the loading task, return the result of success, if the parent class fails to load, the child class itself to try to load, if the child class fails to load throws ClassNotFoundException, this is the parent delegate mode

  • Third-party package loading mode: Reverse delegation mechanism

There are many Service Provider interfaces (SPI) in Java applications, which allow third parties to provide implementations for them. Common SPI include JDBC, JNDI, etc. The interfaces of these SPI belong to Java core libraries. It is generally stored in rt.jar packages and loaded by the Bootstrap class loader. However, the Bootstrap class loader cannot directly load the SPI implementation class, nor can it reverse delegate the SPI implementation class of the AppClassLoader due to the existence of the parental delegation mode. In this case, we need a special class loader to load third-party libraries, and thread-context class loaders (destroyers of the parent-delegate model) are a good choice.

It can be seen from the figure that the rt.jar core package is loaded by the Bootstrap class loader, which contains SPI core interface classes. Since classes in SPI often need to call methods of external implementation classes, Jdbc.jar containing external implementation classes (jdbc.jar exists in the classpath path) cannot be loaded by the Bootstrap class loader, so you have to delegate the thread context class loader to load the implementation classes in jdbc.jar into memory for use by spI-related classes. Obviously, this thread-context classloader loading method breaks the “parent delegate model” by abandoning the parent delegate chain mode during execution, allowing programs to use class loaders in reverse, and of course making Java classloaders more flexible.

  • Sandbox security mechanism

Java \lang\String.class (rt.jar); Java \lang\ string.class Error message indicating that there is no main method due to the loaded rt.jar class String. This ensures the protection of the Java core source code, which is called sandbox security.

IT brother

A big factory to do advanced Java development program ape

Follow wechat public account: IT elder brother

Java foundation, Java Web, JavaEE all tutorials, including Spring Boot, etc

Reply: Resume template, you can get 100 beautiful resumes

Reply: Java learning route, you can get the latest and most complete a learning roadmap

Re: Java ebooks, get 13 must-read books for top programmers