JVM Middle Chapter: Bytecode and Class Loading Chapter 04-Talk about class loader again

JVM Middle Chapter: Bytecode and Class Loading Chapter 04-Talk about class loader again

Note source: Full set of JVM tutorials in Silicon Valley, millions of broadcasts, the peak of the whole network (Song Hongkang explains the java virtual machine in detail)

Synchronous update: gitee.com/vectorx/NOT...

codechina.csdn.net/qq_35925558...

github.com/uxiahnan/NO...

@[toc]

1 Overview

The class loader is the prerequisite for the JVM to execute the class loading mechanism.

The role of ClassLoader:

ClassLoader is the core component of Java. All Classes are loaded by ClassLoader. ClassLoader is responsible for reading the binary data stream of Class information into the JVM through various methods and converting it into a java.lang.Class object corresponding to the target class. Instance. Then hand it over to the Java virtual machine for linking, initialization and other operations. Therefore, the ClassLoader can only affect the loading of the class during the entire loading phase, but cannot change the linking and initialization behavior of the class through the ClassLoader. As for whether it can run, it is determined by Execution Engine.

1.1. Interview questions

Ant Financial:

In-depth analysis of ClassLoader, parent delegation mechanism

What is the parent delegation model of the class loader? One side: Parental delegation mechanism and reasons for use

Baidu:

What class loaders are there, and which files are loaded by these class loaders?

Handwriting a class loader Demo

What is the difference between the forName of Class ("java.lang.String") and the Loadclass ("java.lang.String") of getClassLoader() of Class?

Tencent:

What is the parental delegation model?

What are the class loaders?

Xiaomi:

An introduction to the parent delegation model

Didi:

Briefly talk about the side of the class loader you know: talk about the parent delegation model and its advantages

Byte bounce:

What are class loaders and what are the class loaders?

Jingdong:

What is the parent delegation model of the class loader?

Can the parent delegation mechanism be broken? why

1.2. Classification of class loaders

Class loading classification: explicit loading vs implicit loading

The way of explicit loading and implicit loading of the class file refers to the way the JVM loads the class file into the memory.

  • Explicit loading refers to loading the class object by calling ClassLoader in the code, such as directly using Class.forName(name) or this.getClass().getClassLoader().loadClass() to load the class object.
  • Implicit loading is not directly calling the ClassLoader method to load the class object in the code, but automatically loading it into the memory through the virtual machine. For example, when the class file of a certain class is loaded, another one is referenced in the class file of the class. The object of the class, at this time the additional referenced class will be automatically loaded into the memory through the JVM.

In daily development, the above two methods are generally mixed.

//Implicitly load User user = new User(); //Explicitly load and initialize Class clazz=Class.forName( "com.test.java.User" ); //Explicitly load, but do not initialize ClassLoader. getSystemClassLoader().loadClass( "com.test.java.Parent" ); Copy code

1.3. The Necessity of Class Loaders

Under normal circumstances, Java developers do not need to explicitly use the class loader in the program, but it is very important to understand the loading mechanism of the class loader. From the following aspects:

  • Avoid being at a loss when you encounter java.lang.ClassNotFoundException or java.lang.NoClassDefFoundError during development. Only by understanding the loading mechanism of the class loader can you quickly locate and solve the problem based on the error exception log when an exception occurs
  • When you need to support dynamic loading of classes or need to perform encryption and decryption operations on compiled bytecode files, you need to deal with the class loader.
  • Developers can write custom class loader in the program to redefine the loading rules of the class in order to implement some custom processing logic.

1.4. Namespace

What is the uniqueness of a class?

For any class, the class loader that loads it and the class itself need to confirm that it is inJavaUniqueness in the virtual machine.\color{red}{For any class, the class loader that loads it needs to confirm its uniqueness in the Java virtual machine together with the class itself. }Each class loader has an independent class namespace:Comparing whether two classes are equal is meaningful only if the two classes are loaded by the same class loader.\color{red}{Compares whether two classes are equal, it only makes sense if the two classes are loaded by the same class loader. }Otherwise, even if these two classes originate from the same Class file and are loaded by the same virtual machine, as long as the class loader that loads them is different, the two classes must be unequal.

Namespaces

  • Each class loader has its own namespace, the namespace is composed of the loader and all the classes loaded by the parent loader

  • In the same namespace, two classes with the same complete name (including the package name of the class) will not appear

  • In different namespaces, there may be two classes with the same complete name (including the package name of the class)

In large applications, we often use this feature to run different versions of the same class.

1.5. The basic characteristics of the class loading mechanism

Parent delegation model. But not all class loading follow this model. Sometimes, the type loaded by the startup class loader may need to load user code, such as the ServiceProvider/ServiceLoader mechanism inside the JDK. Users can provide their own on the standard API framework. The JDK also needs to provide some default reference implementations. For example, many aspects of Java, such as JNDI, JDBC, file system, Cipher, etc., all use this mechanism. In this case, the parent delegation model will not be used to load, but the so-called context loader will be used.

Visibility, The child class loader can access the type loaded by the parent loader, but the reverse is not allowed. Otherwise, because of the lack of necessary isolation, we have no way to use the class loader to implement the logic of the container.

Unity, Since the type of the parent loader is visible to the child loader, the type loaded in the parent loader will not be loaded repeatedly in the child loader. Note, however, that the same type can still be loaded multiple times between the "neighbors" of the class loader because they are not visible to each other.

1.6. The relationship between class loaders

Launcher core code

Launcher.ExtClassLoader var1; try { var1 = Launcher.ExtClassLoader.getExtClassLoader(); } catch (IOException var10) { throw new InternalError( "Could not create extension class loader" , var10); } try { this .loader = Launcher.AppClassLoader.getAppClassLoader(var1); } catch (IOException var9) { throw new InternalError( "Could not create application class loader" , var9); } Thread.currentThread().setContextClassLoader( this .loader); Copy code
  • The Parent class of ExtClassLoader is null

  • The Parent class of AppClassLoader is ExtClassLoader

  • The ClassLoader of the current thread is AppClassLoader

Note that hereParentClass is notJavaInheritance in the linguistic sense, but an inclusive relationship\color{red}{Note that the Parent class here is not an inheritance relationship in the sense of the Java language, but a containment relationship}


2. Class loader classification

JVM supports two types of class loaders, namely Bootstrap ClassLoader and User-Defined ClassLoader.

Conceptually, a custom class loader generally refers to a class loader customized by the developer in the program, but the Java virtual machine specification does not define this, but loads all classes derived from the abstract class ClassLoader All are divided into custom class loaders. No matter how the type of class loader is divided, our most common class loader structure in the program is mainly as follows:

  • Except for the top-level startup class loader, all other class loaders should have their own "parent class" adders.
  • Different class loaders seem to have an inheritance relationship, but they are actually containment relationships. In the lower loader, a reference to the upper loader is included.

The relationship between the parent class loader and the child class loader:

class ClassLoader { ClassLoader parent; //The parent class loader public ClassLoader (ClassLoader parent) { this .parent = parent; } } class ParentClassLoader extends ClassLoader { public ParentClassLoader (ClassLoader parent) { super (parent); } } class ChildClassLoader extends ClassLoader { public ChildClassLoader (ClassLoader parent) {//parent = new ParentClassLoader(); super (parent); } } Copy code

It is precisely because the subclass loader contains a reference to the parent class loader, so the corresponding parent class loader can be obtained through the method of the subclass loader

note:

The startup class loader is written in C/C++ language, and the custom class loader is written in the Java language. Although the extended class loader and the application class loader are written in the Java language by jdk developers, they are also Written in java language, so it is also called a custom class loader

2.1. Boot class loader

Start the class loader (bootstrap class loader, Bootstrap ClassLoader)

  • This class loading is implemented in C/C++ language and is nested inside the JVM.

  • It is used to load the core library of Java (the contents under the JAVAHOME/jre/lib/rt.jar or sun.boot.class.path path). Used to provide the classes needed by the JVM itself.

  • It does not inherit from java.lang.ClassLoader and has no parent loader.

  • For security reasons, Bootstrap startup class loader only loads classes whose package names start with java, javax, sun, etc.

  • Load extension classes and application class loaders, and specify them as their parent class loaders.

    Use -XX:+TraceClassLoading parameter to get.

Is the startup class loader written in C++? Yes!

  • C/C++: Pointer function & function pointer, C++ supports multiple inheritance and is more efficient
  • Java: evolved from C++, (C++)-version, single inheritance
System.out.println( " Start the class loader ******* " ); //Get the path of the api that can be loaded by BootstrapclassLoader URL[] urLs = sun.misc.Launcher.getBootstrapcLassPath().getURLs(); for (URL element: urLs) { System.out.println(element.toExternalForm()); } //Randomly select a class from the above path to see what his class loader is: boot class loader ClassLoader classLoader = java.security.Provider.class.getClassLoader(); System.out.println(classLoader); Copy code

Results of the:

2.2. Extending the class loader

Extension ClassLoader

  • Written in Java language and implemented by sun.misc.Launcher$ExtClassLoader.

  • Inherited from the ClassLoader class

  • The parent class loader is the startup class loader

  • Load the class library from the directory specified by the java.ext.dirs system property, or load the class library from the jre/lib/ext subdirectory of the JDK installation directory. If the JAR created by the user is placed in this directory, it will also be automatically loaded by the extension class loader.

System.out.println( " Extended class loader ); String extDirs =System.getProperty( "java.ext.dirs" ); for (String path :extDirs.split( regex: ";" )){ System.out.println(path); } //Randomly select a class from the above path to see what his class loader is: extended class loader lassLoader classLoader1 = sun.security.ec.CurveDB.class.getClassLoader(); System.out.print1n (classLoader1); .//Sun.misc Launcher $ ExtClassLoader @ 1540e19d copy the code

Results of the:

2.3. System class loader

Application class loader (system class loader, AppClassLoader)

  • Written in java language and implemented by sun.misc.Launcher$AppClassLoader
  • Inherited from the ClassLoader class
  • The parent class loader is the extended class loader
  • It is responsible for loading the class library under the path specified by the environment variable classpath or the system property java.class.path
  • The class loader in the application is the system class loader by default.\color{red}{The class loader in the application is the system class loader by default. }
  • It is the default parent loader of user-defined class loader
  • The class loader can be obtained through the getSystemClassLoader() method of ClassLoader

2.4. User-defined class loader

User-defined class loader

  • In the daily application development of Java, the loading of classes is almost executed by the coordination of the above three types of loaders. When necessary, we can also customize the class loader to customize the way the class is loaded.
  • One of the key factors that reflects the strong vitality and great charm of the Java language is that Java developers can customize the class loader to implement dynamic loading of the class library. The loading source can be a local JAR package or a remote resource on the network. .
  • A very wonderful plug-in mechanism can be achieved through a class loader\color{red}{A very wonderful plug-in mechanism can be achieved through a class loader} , practical cases abound in this regard. For example, the well-known OSGI component framework, and then the plug-in mechanism of Eclipse. The class loader provides a mechanism for applications to dynamically add new functions, which can be implemented without repackaging and publishing the application.
  • Simultaneously,Custom loader can achieve application isolation\color{red}{Custom loader can achieve application isolation} , e.g. Tomcat, Spring middleware component framework and are implemented within the custom loader, and custom loader isolate different component modules. This mechanism is much better than C/C++ programs. It is almost impossible to add new functions to C/C++ programs without modifying them. Just one compatibility can block all good ideas.
  • Custom class loader usually needs to inherit from ClassLoader.

3. Test different class loaders

Each Class object will contain a reference to the ClassLoader that defines it. Ways to obtain ClassLoader

//Get the ClassLoader of the current class clazz.getClassLoader() //Get the ClassLoader of the current thread context Thread.currentThread().getContextClassLoader() //Get the ClassLoader of the system ClassLoader.getSystemClassLoader() Copy code

Description:

  • From the point of view of the program, the boot class loader and the other two class loaders (system class loader and extended class loader) are not loader in the same level. The boot class loader is written in C++ language , And the other two class loaders are written in Java language. Since the boot class loader is not a Java class at all, it can only print out null values in a Java program.
  • The Class object of the array class is not created by the class loader, but is automatically created by the JVM as needed during the Java runtime. For the class loader of the array class, it is returned by Class.getClassLoader(), which is the same as the class loader of the element type in the array; if the element type in the array is a basic data type, the array class has no class loading Of the device.
//Operation result: null String[] strArr = new String[ 6 ]; System.out.println(strArr.getClass().getClassLoader()); //Operation result: sun. misc. Launcher AppCLassLoader 18b4aac2 ClassLoaderTest[] test = new ClassLoaderTest[ 1 ]; System.out.println(test.getClass().getClassLoader()); //Operation result: null int []ints = new int [ 2 ]; System.out.println(ints.getClass().getClassLoader()); Copy code

Code:

public class ClassLoaderTest1 { public static void main (String[] args) { //Get the system class loader ClassLoader systemClassLoader=ClassLoader.getSystemCLassLoader(); System.out.print1n(systemClassLoader); //sun.misc.Launcher$AppCLassLoader@18b4aac2 //Get the extended class loader ClassLoader extClassLoader =systemClassLoader.getParent(); System.out.println(extClassLoader); //sun.misc. Launcher$ExtCLassLoader@1540e19d //Attempt to obtain the boot class loader: failed ClassLoader bootstrapClassLoader =extClassLoader.getParent(); System.out.print1n(bootstrapClassLoader); //null //################################ try { ClassLoader classLoader =Class.forName( "java.lang.String" ).getClassLoader(); System.out.println(classLoader); //Customized classes use the system class loader ClassLoader by default. classLoader1=Class.forName( "com.atguigu.java.ClassLoaderTest1" ).getClassLoader(); System.out.println(classLoader1); //About the loading of the array type: the loader of the class used is the same as the loader of the class of the array elements String[] arrstr = new String[ 10 ]; System.out.println(arrstr.getClass().getClassLoader()); //null: indicates that the boot class loader is used ClassLoaderTest1[] arr1 = new ClassLoaderTest1[ 10 ]; System.out.println(arr1.getClass().getClassLoader()); //sun.misc. Launcher$AppcLassLoader@18b4aac2 int [] arr2 = new int [ 10 ]; System.out.println(arr2.getClass().getClassLoader()); //null: } catch (ClassNotFoundException e) { e.printStackTrace(); } } } Copy code

4. ClassLoader source code analysis

The relationship between ClassLoader and existing classes:

In addition to the loader that comes with the above virtual machine, users can also customize their own class loader. Java provides the abstract class java.lang.ClassLoader, and all user-defined class loaders should inherit the ClassLoader class.

4.1. The main method of ClassLoader

The main method of the abstract class ClassLoader: (there is no internal abstract method)

public Final ClassLoader getParent () to copy the code

Returns the super class loader of this class loader

public Class <?> loadClass (String name) throws ClassNotFoundException copy the code

Load the class named name, and return the result as an instance of the java.lang.Class class. If the class cannot be found, a ClassNotFoundException is returned. The logic in this method is the realization of the parental delegation model.

protected Class <?> findClass (String name) throws ClassNotFoundException copy the code

Find the class whose binary name is name, and return the result as an instance of the java.lang.Class class. This is a protected method. The JVM encourages us to override this method. The custom loader needs to follow the parent delegation mechanism. This method will be called by the loadClass() method after checking the parent class loader.

  • Before JDK1.2, when a custom class is loaded, it always inherits the ClassLoader class and overrides the loadClass method to implement a custom class loading class. However, after JDK1.2, it is no longer recommended that users override the loadClass() method. Instead, it is recommended to write the custom class loading logic in the findClass() method. From the previous analysis, it can be seen that the findClass() method is in the loadClass() ) Method is called, when the parent loader in the loadClass() method fails to load, it will call its own findClass() method to complete the class loading, so as to ensure that the custom class loader also conforms to the parent delegation model.

  • It should be noted that the specific code logic of the findClass() method is not implemented in the ClassLoader class. Instead, the ClassNotFoundException is thrown. At the same time, you should know that the findClass method is usually used with the defineClass method.Under normal circumstances, when customizing the class loader, it will directly overrideClassLoaderoffindClass()Method and write loading rules, get the bytecode of the class to be loaded, convert it into a stream, and then calldefineClass()Method generation classClassObject.\color{red}{Under normal circumstances, when customizing the class loader, it will directly override the findClass() method of the ClassLoader and write the loading rules. After obtaining the bytecode of the class to be loaded, convert it into a stream, and then call defineClass() The method generates the Class object of the class. }

protected Final Class <?> the defineClass (String name, byte [] B, int OFF, int len) copying the code

According to the given instance of byte array b converted to Class, the off and len parameters indicate the position and length of the actual Class information in the byte array, where the byte array b is obtained from the outside by the ClassLoader. This is a protected method and can only be used in a custom ClassLoader subclass.

  • The defineClass() method is used to parse the byte stream into a Class object that the JVM can recognize (the method logic has been implemented in ClassLoader). This method can not only instantiate the class object through the class file, but also instantiate it in other ways The class object, such as receiving the bytecode of a class through the network, and then converting it into a byte byte stream to create the corresponding Class object.

  • defineClass()The method is usually the same asfindClass()Methods are used together, under normal circumstances, when customizing the class loader, it will directly overrideClassLoaderoffindClass()Method and write loading rules, get the bytecode of the class to be loaded, convert it into a stream, and then calldefineClass()Method generation classClassObjectThe/color{red}{defineClass() method is usually used together with the findClass() method. Generally, when customizing the class loader, it will directly override the findClass() method of the ClassLoader and write the loading rules to obtain the class to be loaded After the bytecode is converted into a stream, the defineClass() method is called to generate the Class object of the class}

Simple example:

protected Class<?> findClass(String name) throws ClassNotFoundException { //Get the byte array of the class byte [] classData =getClassData(name); if (classData == null ) { throw new ClassNotFoundException(); } else { //Use defineClass to generate class object return defineClass(name,classData, ,classData.length); } } Copy code
protected Final void resolveClass (Class <?> c) Copy the code

A Java class specified by the link. Using this method, the Class object of the class can be created and resolved at the same time. Earlier, we said that the link phase is mainly to verify the bytecode, allocate memory for class variables and set initial values, while converting the symbolic references in the bytecode file into direct references.

protected Final Class <?> findLoadedClass (String name) Copy the code

Look up the loaded class named name, and return the result as an instance of the java.lang.Class class. This method is final and cannot be modified.

private final ClassLoader parent; copy code

It is also an instance of ClassLoader, and the ClassLoader represented by this field is also called the parent of this ClassLoader. In the process of class loading, ClassLoader may pass certain requests to its parents for processing.

4.2. SecureClassLoader and URLClassLoader

Then SecureClassLoader extended ClassLoader, adding several code sources related to the use (verification of the location of the code source and its certificate) and authorization definition class verification (mainly referring to the access rights to the class source code). Generally we do not Will directly deal with this class, more is related to its subclass URLClassLoader.

As mentioned earlier, ClassLoader is an abstract class, and many methods are empty and not implemented, such as findClass(), findResource(), etc. The URLClassLoader implementation class provides specific implementations for these methods. And added the URLClassPath class to assist in obtaining the Class bytecode stream and other functions.When writing a custom class loader, if there are no too complex requirements, you can directly inheritURLClassLoaderclass\color{red}{When writing a custom class loader, if there are no too complicated requirements, you can directly inherit the URLClassLoader class} so that it can Avoid writing your own findClass() method and the way it gets the bytecode stream, so that the custom class loader is written more concisely.

4.3. ExtClassLoader and AppClassLoader

After understanding URLClassLoader, look at the remaining two class loaders, namely, the extended class loader ExtClassLoader and the system class loader AppClassLoader. Both of these classes inherit from URLClassLoader and are static internal classes of sun.misc.Launcher.

sun.misc.Launcher is mainly used by the system to start the main application. Both ExtClassLoader and AppClassLoader are created by sun.misc.Launcher. The main class structure is as follows:

We found that ExtClassLoader did not override the loadClass() method, which is enough to show that it follows the parental delegation model, while AppClassLoader overloads the loadClass() method, but the parent class loadClass() method is eventually called, so it still complies with the parental delegation model .

4.4. Class.forName() and ClassLoader.loadClass()

Class.forName()

  • Class.forName(): is a static method, the most commonly used is Class.forName(String className);

  • Return a Class object based on the fully qualified name of the passed in class. This method will perform the initialization of the class while loading the Class file into the memory.

    Class.forName( "com.atguigu.java.Helloworld" ); Copy code

ClassLoader.loadClass()

  • ClassLoader.loadClass(): This is an instance method and requires a ClassLoader object to call this method.

  • When this method loads the Class file into the memory, the initialization of the class is not performed, and the initialization is not performed until the class is used for the first time. This method needs to get a ClassLoader object, so you can specify which class loader to use as needed.

    Classloader cl = ......; cl.loadClass( "com.atguigu.java.Helloworld" ); Copy code

5. Parental delegation model

5.1. Definition and essence

Java JDK1.2 Java

5.2.

  • Java ClassLoader \color{red}{Java ClassLoader }

  • API

java.lang.ClassLoader.loadClass(String boolean)

1

2 parent.loadClass(name false)

3 findBootstrapClassorNull(name)

4 3 findClass(name) java.lang.ClassLoader defineClass native Java

2 3

java.lang.Object JDK ]VM javaJang.Object JVM 4 1 2 1 2 null findClass String

java.lang.ClassLoader.loadClass(String) java.lang.ClassLoader.loadclass(String boolean) 4 l 4

JDK java.lang.ClassLoader.defineclass(String byte[] int int ProtectionDomain) preDefineClass() JDK

ClassLoader ClassLoader ClassLoader

Java \color{red}{ Java } Tomcat Serylet

5.3.

Java

Java Java 3

JDK1.2

JDK 1.2 java.lang.ClassLoader Java Java loadClass() \color{red}{ loadClass() } JDK1.2 java.lang.ClassLoader protected findClass() loadClass() loadClass() loadClass() findClass()

\color{red}{ } API \color{red}{ }

JNDI JNDI Java JDK 1.3 rt.jar Java JNDI ClassPath JNDI Service Provider Interface SPI \color{red}{ } SPI Java rt.jar SPI

Java ThreadContextClassLoader \color{red}{ Thread Context ClassLoader } java.lang.Thread setContextClassLoader()

JNDI SPI \color{red}{ } JNDI JDBC JCE JAXB JBI SPI JDK6 JDK java.util.ServiceLoader META-INF/services SPI

** (Hot Swap) (Hot Deployment)**

IBM JSR-291( OSGiR4.2) (osGi Bundle) Bundle Bund1e oSGi

OSGi

1 java. \color{red}{ java.* }

2 \color{red}{ }

3 Import Export Bundle

4 Bundle ClassPath

5 Fragment Bundle Fragment Bundle

6 Dynamic Import Bundle Bund1e

7

OSGi OSGi OSGi

5.4.

\color{red}{ }Basically, most scripting languages naturally support hot replacement, such as PHP. As long as the PHP source file is replaced, the change will take effect immediately without restarting the web server.

But for Java, hot replacement is not inherently supported. If a class has been loaded into the system, by modifying the class file, the system cannot load and redefine the class again. Therefore, a feasible way to achieve this function in Java is to use ClassLoader flexibly.

Note: The classes of the same name loaded by different ClassLoaders belong to different types and cannot be converted and compatible with each other. That is, two different ClassLoaders load the same class. Inside the virtual machine, the two classes are considered completely different.

According to this feature, it can be used to simulate the realization of hot replacement. The basic idea is shown in the figure below:


6. Sandbox security mechanism

Sandbox security mechanism

  • Ensure program safety
  • Protect Java native JDK code

JavaThe core of the security model isJavasandbox(sandbox)\color{red}{The core of the Java security model is the Java sandbox} . What is a sandbox? A sandbox is an environment that restricts the running of programs.

The sandbox mechanism is to put Java codeLimited to virtual machines (JVM) In a specific operating range, and strictly restrict code access to local system resources\color{red}{Limited to the specific operating range of the virtual machine (JVM), and strictly restrict code access to local system resources} . Through such measures to ensure the limited isolation of the code, to prevent damage to the local system.

The sandbox mainly restricts access to system resources. What does the system resource include? CPU, memory, file system, network. Different levels of sandboxes have different restrictions on access to these resources.

All Java programs can run in a designated sandbox and can customize security policies.

6.1. JDK1.0 period

In Java, the execution program is divided into local code and remote code. Local code is regarded as trusted by default, while remote code is regarded as untrusted. For the local code of the credit, all local resources can be accessed. For untrusted remote codes in early Java implementations, security relied on the sandbox mechanism . The JDK1.0 security model is shown in the figure below

6.2. JDK1.1 period

Such a strict security mechanism in JDK1.0 also brings obstacles to the function expansion of the program. For example, when users want remote code to access files in the local system, they cannot be realized.

Therefore, in the subsequent version of Java 1.1, improvements have been made to the security mechanism and a security strategy has been added . Allows users to specify code access to local resources.

The JDK1.1 security model is shown in the figure below

6.3. JDK1.2 period

In the Java 1.2 version, the security mechanism has been improved again, and code signing has been added . Whether local code or remote code is set according to the user's security policy, the class loader is loaded into the virtual machine's operating space with different permissions to achieve differentiated code execution permission control. The JDK1.2 security model is shown in the following figure:

6.4. JDK1.6 period

The current implementation of the latest security mechanism introduces the concept of **Domain**.

The virtual machine loads all codes into different system domains and application domains.The system domain part is dedicated to interacting with key resources\color{red}{The system domain part is dedicated to interacting with key resources} , and each part is applied to the domain access to various resources required by the proxy system domain portion. Different protected domains in the virtual machine correspond to different permissions. The class files that exist in different domains have all the permissions of the current domain, as shown in the figure below, the latest security model (jdk1.6)


7. Custom class loader

7.1. Why do we need to customize the class loader?

  • Load class in isolation\color{red}{Isolated loading class}

    In some frameworks, middleware and application modules are isolated, and classes are loaded into different environments. For example: A certain container framework in Alibaba uses a custom class loader to ensure that the jar package that the application depends on will not affect the jar package used by the middleware runtime. Another example: Web application servers such as Tomcat have several class loaders customized internally to isolate different applications on the same Web application server.

  • Modify the way the class is loaded\color{red}{Modify the way of class loading}

    The loading model of the class is not mandatory. In addition to Bootstrap, other loadings are not necessarily introduced, or dynamically loaded on demand at a certain time according to the actual situation

  • Extension load source\color{red}{Extension load source}

    For example, load from database, network, or even TV set-top box

  • Prevent source code leakage\color{red}{Prevent source code leaks}

    Java code is easy to be compiled and tampered with, and can be compiled and encrypted. Then the class loading also needs to be customized to restore the encrypted bytecode.

Common scenarios

  • To achieve similar in-process isolation, the class loader is actually used as a different namespace to provide a container-like and modular effect. For example, two modules depend on different versions of a certain class library, and if they are loaded by different containers, they will not interfere with each other. The masters in this area are frameworks such as JavaEE, OSGI, and JPMS.
  • The application needs to obtain class definition information from a different data source, such as a network data source, rather than a local file system. Or you need to manipulate the bytecode yourself, dynamically modify or generate types.

note

In general, using different class loaders to load different functional modules will improve the security of the application. However, if Java type conversion is involved, the loader is prone to unpleasant things. When doing Java type conversion, only two types are loaded by the same loader before the type conversion can be performed, otherwise an exception will occur during the conversion.

7.2. Implementation

Java provides the abstract class java.lang.ClassLoader, and all user-defined class loaders should inherit the ClassLoader class.

When customizing the subclasses of ClassLoader, we have two common practices:

  • Method one: rewrite the loadClass() method
  • Method two: rewrite the findclass() method

Compared

  • These two methods are essentially the same, after all, loadClass() will also call findClass(), but logically speaking, we'd better not directly modify the internal logic of loadClass(). The recommended approach is to only rewrite the loading method of the custom class in findClass(), specify the name of the class according to the parameter, and return the reference of the corresponding Class object.
  • The loadclass() method is the place where the logic of the parent delegation model is implemented. Modifying this method without authorization will cause the model to be damaged and easily cause problems.Therefore, it is best for us to make small-scale changes within the framework of the parental delegation model without destroying the original stable structure.\color{red}{Therefore, it is best for us to make small-scale changes within the framework of the parent delegation model, so as not to destroy the original stable structure} . At the same time, it also avoids the need to write the repetitive code of the parent delegation in the process of rewriting the loadClass() method. From the perspective of code reusability, it is always a better choice not to directly modify this method.
  • After the custom class loader is written, the loadClass() method can be called in the program to implement the class loading operation.

Description

  • The parent class loader is the system class loader
  • All class loading in JVM will use java.lang.ClassLoader.loadClass(String) interface (except for custom class loader and rewrite java.lang.ClassLoader.loadClass(String) interface), even the core class library of JDK No exceptions.

8. New Features of Java9

In order to ensure compatibility, JDK9 did not fundamentally change the three-tier class loader architecture and parent delegation model, but for the smooth operation of the modular system, there are still some changes worth noting.

  1. The extension mechanism was removed, the extension class loader was retained for backward compatibility reasons, but was renamed to the platform class loader (platform class loader). It can be obtained through the new method getPlatformClassLoader() of classLoader.

    JDK9 was built based on modularity (the original rt.jar and tools.jar were split into dozens of JMOD files), and the Java class library has naturally met the scalability requirements, so naturally there is no need to keep it< JAVA_HOME>\lib\ext directory, the mechanism of using this directory or the java.ext.dirs system variable to extend the JDK function before has no longer existed value.

  2. Both the platform class loader and the application class loader no longer inherit from java.net.URLClassLoader.

    Now the startup class loader, platform class loader, and application class loader all inherit from jdk.internal.loader.BuiltinClassLoader.

If a program directly relies on this inheritance relationship, or relies on a specific method of the URLClassLoader class, the code is likely to crash in JDK9 and higher versions of JDK.

  1. In Java 9, the class loader has a name. The name is specified in the constructor and can be obtained through the getName() method. The name of the platform class loader is platform, and the name of the application class loader is app. The name of the class loader can be very useful when debugging issues related to the class loader.
  2. The startup class loader is now a class loader (previously implemented in C++) implemented in cooperation with the java class library inside the jvm. However, in order to be compatible with the previous code, it will still return null in the scene of obtaining the startup class loader. You will get an instance of BootClassLoader.
  3. The delegation relationship for class loading has also changed. When the platform and application class loader receives a class loading request, before delegating to the parent loader to load, it must first determine whether the class can belong to a certain system module. If such an attribution relationship can be found, it must be delegated first Finish loading for the loader responsible for that module.

Code:

public class ClassLoaderTest { public static void main (String[] args) { System.out.println(ClassLoaderTest.class.getClassLoader()); System.out.println(ClassLoaderTest.class.getClassLoader().getParent()); System.out.println(ClassLoaderTest.class.getClassLoader().getParent().getParent()); //Get the system class loader System.out.println(ClassLoader.getSystemClassLoader()); //Get the platform class loader System.out.println(ClassLoader.getPlatformClassLoader()); //Get the name of the loader of the class System.out.println(ClassLoaderTest.class.getClassLoader().getName()); } } Copy code

Previous <JVM Middle Part: Bytecode and Class Loading> 03-Detailed explanation of class loading process (class life cycle)