Note source: Silicon Valley JVM full tutorial, one million playback, the whole network peak (Song Hongkang detailed Java virtual machine)

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

https://codechina.csdn.net/qq…

https://github.com/uxiahnan/N…

[toc]

1. An overview of the

The classloader is a prerequisite for the JVM to implement the classloading mechanism.

ClassLoader:

Classloaders are the core components of Java. All classes are loaded by classloaders. Classloaders are responsible for reading binary streams of Class information into the JVM by various means. Convert to an instance of a java.lang.Class object corresponding to the target Class. Then it is handed 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, and cannot change the linking and initialization behavior of the class through the ClassLoader. Whether it runs or not is the Execution Engine’s decision.

1.1. Interview questions for Dachang

<mark> : </mark>

In-depth analysis of ClassLoader, parental delegation mechanism

What is the parent delegate model for the classloader? One: Parental delegation mechanism and reasons for its use

<mark> baidu: </mark>

What class loaders do they have, and what files do they load?

Handwrite a class loader Demo

What’s the difference between a Class’s forName (” java.lang.string “) and a Class’s getClassLoader () loadClass (” java.lang.string “)?

Tencent: </mark>

What is the parental delegate model?

What are class loaders?

<mark> millet: </mark>

The parental delegate model is introduced

<mark> Didi: </mark>

A little bit about what you know about classloaders: talk about the parent delegate model and its benefits

<mark> byte jump: </mark>

What is a class loader and what are the class loaders?

<mark>京东:</mark>

What is the parent delegate model for the classloader?

Can the parental delegation mechanism be broken? why

1.2. Classification of class loaders

Class loading classification: explicit loading vs. implicit loading

Explicit and implicit loading of class files refers to how the JVM loads class files into memory.

  • Explicitly loading refers to loading a class object in code by calling ClassLoader, such as directly using Class.forName(name) or this.getClass().getClassLoader().loadClass().
  • Implicitly loaded class objects are not directly loaded in code by calling ClassLoader methods, but are automatically loaded into memory by the virtual machine. For example, when a class file of a class is loaded, the class file of that class references objects of another class. At this time, the extra referenced classes will be automatically loaded into memory by the JVM.

These two methods are often mixed in daily development.

// implicitly load User User =new User(); // explicitly load and initialize Class clazz= class.forName (" com.test.java.user "); / / explicitly load, but not initialized. This getSystemClassLoader (). The loadClass (" com. Test. Java. The Parent ");

1.3. Necessity of class loaders

In general, Java developers do not need to explicitly use classloaders in their programs, but it is important to understand how classloaders load. From the following aspects:

  • Avoid in development in Java. Lang. ClassNotFoundException exception or Java. Lang. A NoClassDefFoundError, unprepared. Only by understanding the loading mechanism of the classloader can we quickly locate the problem and resolve the problem based on the error exception log when an exception occurs
  • When you need to support dynamic loading of classes or you need to encrypt and decrypt a compiled bytecode file, you need to deal with a classloader.
  • Developers can write custom classloaders in their programs to redefine the class loading rules to implement some custom processing logic.

1.4. Namespaces

What is the uniqueness of classes?

$\color{red}{For any class, it is up to the classloader that loads it and the class itself to verify its uniqueness in the Java Virtual Machine. }$Each class loader has a separate class namespace: $\color{red}{Comparison of two classes for equality only makes sense if the two classes are loaded by the same class loader. }$Otherwise, even if the two classes originate from the same Class file and are loaded from the same virtual machine, the two classes are bound to be unequal as long as they are loaded by different classloaders.

The namespace

  • Each classloader has its own namespace, which consists of classes loaded by that loader and all parent loaders
  • Two classes with the same full name (including the package name of the class) will never appear in the same namespace
  • In different namespaces, it is possible to have two classes whose full name (including the package name of the class) is the same

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

1.5. Basic characteristics of class loading mechanism

Parental delegate model. But not all class loading to comply with this model, sometimes, to start the class loader the type of load, it is possible to load the user code, such as the inside of the JDK ServiceProvider/ServiceLoader mechanism, the user can on standard API framework, to provide their own implementation, The JDK also needs to provide some default reference implementation. For example, many aspects of Java such as JNDI, JDBC, the file system, Cipher, etc., use this mechanism, which does not use the parental delegate model to load, but instead uses what is called a context loader.

<mark> visibility </mark>, the subclass loader can access the type loaded by the parent loader, but the reverse is not allowed. Otherwise, we would not be able to implement the container logic with class loaders because of the lack of the necessary isolation.

<mark> single </mark>, since the type of the parent loader is visible to the child loader, the type that has been loaded in the parent loader will not be reloaded in the child loader. Note, however, that the same type can still be loaded multiple times between classloader “neighbors” because they are not visible to each other.

1.6. Relationship between class loaders

Launcher class 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);
  • The Parent class of ExtClassLoader is null
  • The Parent class of AppClassLoader is ExtClassLoader
  • The current thread’s ClassLoader is AppClassLoader

$\color{red}{Note that the Parent class is not an inheritance relationship in the Java language, but an inclusion relationship}$

<hr/>

2. Loader classification of classes

The JVM supports two types of classloaders, the Bootstrap ClassLoader and the User-defined ClassLoader.

Conceptually, a custom ClassLoader generally refers to a class of class loaders in a program that is customized by the developer, but the Java Virtual Machine specification does not define it this way. Instead, it classifies all classloaders that derive from the abstract class ClassLoader as custom classloaders. Regardless of the class loader type, the most common class loader structure in a program is as follows:

  • All class loaders, except the top-level startup class loader, should have their own “parent” adder.
  • Different class loaders seem to be Inheritance relationships, but they are actually inclusion relationships. In the lower loader, contains a reference to the upper loader.

Relationship between parent and subclass loaders:

class ClassLoader{ ClassLoader parent; 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); }}

Because the subclass loader contains a reference to the superclass loader, the corresponding superclass loader can be obtained through the methods of the subclass loader

Note:

Start-up classloaders are written in C/C++, while custom classloaders are written in the Java language. Extended classloaders and application classloaders are also written in the Java language, and are therefore referred to as custom classloaders, although they are written in the Java language by JDK developers

2.1. Boot the classloader

<mark> Bootstrap ClassLoader </mark> </mark> Bootstrap ClassLoader </mark>

  • This class loading is implemented using the C/C++ language and is nested within the JVM.
  • It is used to load Java’s core libraries (JAVAHOME/jre/lib/rt.jar or the contents under the sun.boot.class.path path). Used to provide the classes needed by the JVM itself.
  • ClassLoader does not inherit from java.lang.ClassLoader and does not have a parent loader.
  • For security reasons, the Bootstrap loader only loads classes starting with package names Java, javax, sun, etc
  • Loads the extension classes and application class loaders, and specifies as their parent class loaders.





    Use the -XX:+ traceClassLoading parameter.

Start the class loader written in C++? Yes!

  • C/C++ : Pointer Functions & Function Pointers, C++ support multiple inheritance, more efficient
  • Java: Evolved from C++, (C++) – version, single inheritance
System.out.println("********** start classloader is normal "); / / get BootstrapclassLoader can load the path of the API URL [] urLs = sun. Misc. The Launcher. GetBootstrapcLassPath (.) getURLs (); for (URL element : urLs) { System.out.println(element.toExternalForm()); } / / from the above path choice of a class, let's see what his class loader is: the bootstrap class loader this this = Java security. The Provider. The class. The getClassLoader (); System.out.println(classLoader);

Execution Result:

2.2. Extending the classloader

<mark> Extension ClassLoader </mark>

  • Java language, by sun.misc.launcher $ExtClassLoader implementation.
  • Inherits from the ClassLoader class
  • The parent class loader is the boot class loader
  • Loads the class libraries from the directory specified by the java.ext.dirs system property, or from the JDK’s installation directory under the jre/lib/ext subdirectory. If the user-created JAR is placed in this directory, it will also be automatically loaded by the extended class loader.

System.out.println("*********** extension classloader is normal "); String extDirs =System.getProperty("java.ext.dirs"); for (String path :extDirs.split( regex:";" )){ System.out.println(path); } / / from the above path choice of a class, let's see what's his class loader: extension class loader lassLoader classLoader1 = sun. Security. Ec. CurveDB. Class. GetClassLoader (); System.out.print1n(classLoader1); //sun.misc. Launcher$ExtCLassLoader@1540e19d

Execution Result:

2.3. System class loader

<mark> application classloader (system classloader, AppClassLoader) </mark>

  • Java language, by sun.misc.launcher $AppClassLoader implementation
  • Inherits from the ClassLoader class
  • The parent class loader is the extended class loader
  • It is responsible for loading libraries under the environment variable CLASSPATH or the path specified by the system property java.class.PATH
  • $\color{red}{The classloader in the application is the system classloader by default. } $
  • It is the default parent of a user-defined classloader
  • The ClassLoader is obtained through the ClassLoader’s getSystemClassLoader() method

2.4. User-defined classloaders

<mark> User Custom Class Loader </mark>

  • In everyday Java application development, class loading is almost performed by the above three class loaders in cooperation. If necessary, we can also customize the class loader to customize the way the class is loaded.
  • One of the key factors to the vitality and charm of the Java language is that Java developers can customize class loaders to dynamically load class libraries from either local JARs or remote resources on the network.
  • $\color{red}{classloaders can implement a very nice plug-in mechanism}$, and there are countless examples of this in action. For example, the well-known OSGi component framework, or Eclipse’s plug-in mechanism. Classloaders provide an application with a mechanism to dynamically add new functionality without repackaging the published application.
  • At the same time, $\color{red}{custom loader can achieve application isolation}$, such as Tomcat, Spring and other middleware and component frameworks have internal implementation of the custom loader, and through the custom loader isolation of different component modules. This mechanism is so much better than C/C++ programs that it’s almost impossible to add functionality to a C/C++ program without modifying it, and a single compatibility can block all good ideas.
  • Custom classloaders usually need to inherit from classloaders.

<hr/>

3. Test different class loaders

Each Class object will contain a reference to the ClassLoader that defines it. The way to get the ClassLoader

}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} Get the system this this. GetSystemClassLoader ()

Description:

  • From the perspective of the program, the bootstrap classloader is not a loader in the same hierarchy as the other two classloaders (the system class loader and the extended class loader), which are written in C++ and the other two classloaders are written in Java. Because the bootstrap classloader is not a Java class at all, only empty values are printed in Java programs.
  • The Class objects of the array Class are not created by the Class loader, but are automatically created by the JVM as needed at Java runtime. For the Class loader of the array Class, this is returned via Class.getClassLoader(), the same as for the element type in the array. If the element type in the array is a primitive data type, the array class does not have a class loader.
String[] strArr = new String[6]; System.out.println(strArr.getClass().getClassLoader()); Sun.misc.launcher $appClassLoader @18b4aac2 classLoaderTest [] test=new classLoaderTest [1]; System.out.println(test.getClass().getClassLoader()); Int []ints =new int[2]; int[]ints =new int[2]; System.out.println(ints.getClass().getClassLoader());

Code:

Public class LoaderTest1{public static void main(String[] args) {public class LoaderTest1{public static void main(String[] args) systemClassLoader=ClassLoader.getSystemCLassLoader(); System.out.print1n(systemClassLoader); / / sun. Misc. 18 b4aac2 / / get the Launcher $AppCLassLoader @ extension class loader this extClassLoader = systemClassLoader. The getParent (); System.out.println(extClassLoader); // Sun.misc.launcher $ExtCLassLoader@1540e19d // Attempts to get bootstrap classloader: Fail ClassLoader bootstrapClassLoader = ExtClassLoader.getParent (); System.out.print1n(bootstrapClassLoader); //null //################################## try{ ClassLoader classLoader =Class.forName("java.lang.String").getClassLoader(); System.out.println(classLoader); / / the custom of the default system Class loader this classLoader1 = Class. Class.forname (" com. Atguigu. Java. ClassLoaderTest1 "). The getClassLoader (); System.out.println(classLoader1); String[] arrStr = new String[10]; arrStr = new String[10]; arrStr = new String[10]; arrStr = new String[10]; System.out.println(arrstr.getClass().getClassLoader()); //null: means that the bootloader 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(); }}}

<hr/>

4. ClassLoader source code parsing

Relationship between ClassLoader and Existing Classes:

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

4.1. Main methods of ClassLoader

The main methods of the abstract class ClassLoader :(there are no abstract methods inside)

public final ClassLoader getParent()

Returns the superclassloader of the class loader

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

Load a Class named Name and return an instance of the java.lang.Class Class. If the class is not found, the ClassNotFoundException exception is returned. The logic in this method is the implementation of the parental delegate pattern.

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

Java.lang.class = java.lang.class = java.lang.class = java.lang.class = java.lang.class = java.lang.class = java.lang.class; This is a protected method that the JVM encourages us to override, requiring the custom loader to follow the parental delegate mechanism, which is called by the loadClass() method after checking the parent class loader.

  • Prior to JDK1.2, it was always possible to implement custom classloaded classes by inheriting the ClassLoader class and overwriting the loadClass method when a custom class was loaded. However, since JDK1.2, users are no longer advised to override the loadClass() method. Instead, custom class loading logic is recommended to be written in the findClass() method. From the above analysis, the findClass() method is called in the loadClass() method. When the parent loader in the loadClass() method fails to load, its own findClass() method is called to complete the class loading, thus ensuring that the custom class loader also conforms to the parental delegate pattern.
  • Note that there is no specific code logic to implement the findClass() method in the ClassLoader class. Instead, it throws a ClassNotFoundException, and it should be noted that the findClass method is usually used with the defineClass method. $\color{red}{Normally, when you customize a ClassLoader, you directly override the ClassLoader’s findClass() method and write the loading rule, take the bytecode of the Class to load, convert it to a stream, and then call the defineClass() method to generate the Class object. } $
protected final Class<? > defineClass(String name, byte[] b,int off,int len)

The off and len parameters represent the location and length of the actual Class information in the Byte array, where the Byte array B is externally retrieved 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 a byte stream into a Class object that is recognized by the JVM (this logic is implemented in the ClassLoader) and is used to instantiate a Class object not only from a Class file, but in other ways as well. For example, the bytecode of a Class is received over the network, and then converted into a byte stream to create the corresponding Class object.
  • The $\color{red}{defineClass() method is usually used in conjunction with the findClass() method. Normally, when you customize the ClassLoader, you override the findClass() method of the ClassLoader directly and write the loading rule, which takes the bytecode of the class to load and converts it to a stream. Then call the defineClass() method to generate the Class object}$

Simple examples:

protected Class<? > findClass(String Name) throws ClassNotFoundException {byte[] classData =getClassData(Name); if (classData == null) { throw new ClassNotFoundException(); } else{// generate class object with defineClass return defineClass(name,classData,θ,classData.length); }}
protected final void resolveClass(Class<? > c)

Link to a Java class specified. Using this method, the Class object of the Class can be created as well as resolved. We said earlier that the linking phase is mainly about validating the bytecode, allocating memory and setting initial values for class variables, and converting symbolic references in the bytecode file to direct references.

protected final Class<? > findLoadedClass(String name)

Returns an instance of the java.lang.class Class that has been loaded. This method is final and cannot be modified.

private final ClassLoader parent;

It is also an instance of a ClassLoader, and the ClassLoader represented by this field is also called the parent of the ClassLoader. During class loading, the ClassLoader may hand over some requests to its parents.

4.2. The SecureClassLoader and URLClassLoader

SecureClassLoader then extends ClassLoader by adding several methods related to the use of the source code (validation of the source code’s location and its certificates) and permissions to define class validation (primarily access to the class source code), which we would not normally deal with directly. It is more associated with its subclass URLClassLoader.

As mentioned earlier, ClassLoader is an abstract class and many methods are empty and unimplemented, such as findClass(), findResource(), etc. The URLClassLoader implementation class provides concrete implementations for these methods. The URLClasspath Class has also been added to assist in obtaining Class bytecode streams and other functions. $\color{red}{When writing a custom classloader, if you don’t have too complicated a requirement, you can directly inherit the URLClassLoader class}$. This can make writing a custom classloader much simpler by avoiding having to write the findClass() method and the way it gets the bytecode stream.

4.3. ExtClassLoader与AppClassLoader

After learning about the URLClassLoader, let’s look at the remaining two classloaders, the extended classloader ExtClassLoader and the system classloader AppClassLoader, both of which inherit from the URLClassLoader. Is a static inner class for sun.misc.Launcher.

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

We find that ExtClassLoader does not override the loadClass() method, which is sufficient to indicate that it follows the parental delegate pattern, while AppClassLoader overrides the loadClass() method, but ultimately calls the parent loadClass() method. So the parental delegate pattern is still observed.

4.4 Class. Class.forname () with this. LoadClass ()

Class.forName()

  • Class.forName() : is a static method, most commonly used is Class.forName(String className);
  • Returns a Class object based on the fully qualified name of the Class passed in. This method performs Class initialization while loading the Class file into memory.

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

ClassLoader.loadClass()

  • ClassLoader.loadClass() : This is an instance method and requires a classLoader object to call the method.
  • When this method loads the Class file into memory, it does not initialize the Class until the first time the Class is used. This method, because it needs to get a ClassLoader object, can specify which ClassLoader to use as needed.

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

<hr/>

5. Parental delegate model

5.1. Definition and essence

The class loader is used to load classes into the Java Virtual Machine. Starting with JDK1.2, classes are loaded using a parental delegate mechanism, which is better for the security of the Java platform.

define

If a class loader receives a request to load a class, it first does not attempt to load the class itself, but delegates the request to the parent class loader, recursively, and returns successfully if the parent class loader can complete the class loading task. Only if the parent class loader is unable to complete the loading task will it load itself.

nature

The order of class loading is specified as follows: the bootstrap class loader loads first; if not loaded, the extension class loader loads; if not loaded, the system class loader or the custom class loader loads.

5.2. Strengths and disadvantages

Parental delegation mechanism advantages

  • Avoid repeated class loading to ensure the global uniqueness of a class

    $\color{red}{Java class has a priority hierarchy along with its classloaders. This hierarchy prevents the class from being reloaded. When the parent has already loaded the class, there is no need for the child ClassLoader to load it again. } $

  • Secure the application and prevent the core API from being tampered with arbitrarily

The code to support

Parents delegate mechanism in Java. Lang. This. LoadClass (String, Boolean) in the interface. The logic of this interface is as follows:

(1) First search for the target class in the cache of the current loader, and return it directly if there is.

(2) determine whether the parent of the current loader is empty, if not, call Parent.loadClass (name, false) interface to load.

(3) On the other hand, if the parent class loader of the current loader is empty, the FindBootstrapClassorNull (Name) interface is called to let the boot class loader load.

(4) If the above three paths fail to load successfully, then call the FindClass (Name) interface to load. This interface will eventually load the target Java class by calling the native interface of the DefineClass family of the java.lang.ClassLoader interface.

The model for the parent delegate is hidden in steps 2 and 3.

For example,

Assuming you are loading the java.lang.Object class, it is obvious that this class is one of the most core-core classes in the JDK, and therefore must be loaded only by the bootstrap classloader. When the VM is ready to load javajang. Object, the JVM will use the system class loader by default. Follow the logic of the above 4 steps to load the class. Since the parent of the slave class loader is the extended class loader, the extended class loader continues to repeat from step 1. Since the class must also not be found in the extended classloader’s cache, proceed to step 2. The parent loader of the extended class is null, so the system calls findClass (String), which is eventually loaded through the bootstrap classloader.

thinking

If the custom class loader rewritten in Java. Lang. This. LoadClass (String) or Java. Lang. This. LoadClass (String, Boolean) method, to erase one of the parents delegate mechanism, By keeping only steps L and 4 of the above four, are the core libraries ready to load?

That won’t work either! Because the JDK also provides a layer of protection for the core class libraries. Custom class loaders, and system class loader or extension class loader, finally all must call Java lang. This. The defineclass (String, byte [], int, int, ProtectionDomain) method, This method, in turn, executes the predefineClass () interface, which provides protection for the JDK core class library.

disadvantages

The delegate process for checking whether a class is loaded is one-way. While this approach is structurally clear and makes the responsibilities of the individual classloaders very clear, it also introduces the problem that the top-level ClassLoader cannot access the classes loaded by the lower-level classloaders.

Typically, the classes in the boot class loader are the system core classes, including some important system interfaces, while in the application class loader, they are the application classes. In this pattern, there is no problem with application classes accessing system classes, but there is a problem with system classes accessing application classes. For example, an interface is provided in a system class that needs to be implemented in an application class, and the interface is bound to a factory method to create an instance of the interface. Both the interface and the factory method are in the boot class loader. At this point, the factory method is unable to create an application instance loaded by the application class loader.

conclusion

$\color{red}{Since the Java Virtual Machine specification does not explicitly require the classloader’s loading mechanism to use the parental delegate model, it is only recommended that it be so. }$For example, in Tomcat, the loading mechanism used by the class loader is different from the traditional parental delegate model. When the default class loader receives a class loading task, it will first load the class itself. When it fails to load the class, it will delegate the class loading task to its superclass loader. This is also a practice recommended by the Serylet specification.

5.3. Disrupt the parental delegation mechanism

The parental delegate model is not a model with mandatory constraints, but rather an implementation of class loaders recommended by Java designers to developers.

Most classloaders in the Java world have followed this model, with a few exceptions, and until the advent of Java modularity, the parent delegate model had been “broken” on three large scale.

The parent delegate mechanism is broken for the first time

The first “breakage” of the parent delegate model actually occurred before the parent delegate model-in the “ancient” days before JDK1.2 came out.

Since the parental delegate model was introduced only after JDK 1.2, the concept of class loaders and the abstract class java.lang.ClassLoader existed in the first release of Java. In the face of existing user-defined ClassLoader code, The Java designers had to make some compromises when they introduced the parent delegate model. $\color{red}{in order to be compatible with the existing code, there is no technical way to avoid the possibility of loadClass() being overridden by subclasses}$, You can only add a new protected method, findClass(), to java.lang.ClassLoader after JDK1.2, and override this method as much as possible when guiding user-written classloading logic, rather than writing code in loadClass(). In the previous section, we analyzed the loadClass() method, where the logic of the parent delegate is implemented. According to the logic of loadClass(), if the parent class fails to load, it will automatically call its own findClass() method to complete the load, which does not affect the user’s ability to load the class according to their own wishes. You can also ensure that newly written classloaders conform to the parental delegate rules.

The second parental delegate mechanism is broken: the thread-context classloader

The second “breakage” of the parental delegate model is caused by a flaw in the model itself. Parent delegation is a good solution to the problem of consistency of the underlying type when the classloaders cooperate ($\color{red}{the more basic class is loaded by the higher loader}$). The underlying type is called “base”. Because they always exist as APIs that are inherited and called by the user’s code, but programming often doesn’t have perfect rules that are absolutely fixed. What if there is a $\color{red}{base type that needs to be called back to the user’s code? } $

A typical example of this is the JNDI service, which is now a standard Java service, and whose code is loaded by the boot classloader (added to rt.jar in JDK 1.3), and is certainly a very basic type in Java. But the purpose of JNDI is to find and centrally manage resources, and it calls the code of the JNDI Service Provider Interface (SPI) implemented by another vendor and deployed under the application’s ClassPath. Now the question is, $\color{red}{if the class loader is started, it is impossible to read and load the code. }$<u> (SPI: In the Java platform, the interface in the core class rt.jar that provides external services and can be self-implemented by the application layer is usually called SPI) </u>

To solve this dilemma, the Java design team had to introduce a less elegant design: $\color{red}{Thread Context ClassLoader}$. This class loader can be set using the setContextClassLoader() method of java.lang.Thread class. If it is not already set when the Thread is created, it will inherit one from the parent Thread. If it is not set in the global scope of the application, it will inherit one from the parent Thread. The default class loader is the application class loader.

With thread-context classloaders, programs can do some “corrupt” things. The JNDI service uses the thread-context class loader to load the required SPI service code. $\color{red}{this is the behavior of the parent class loader to request the child class loader to complete the class loading. This behavior actually breaks through the hierarchy of the parent delegate model to use the class loader in reverse. The general principles of the parental delegate model are violated, but there is nothing to be done about it. , such as JNDI, JDBC, JCE, JAXB, JBI, etc. However, when the SPI has more than one service provider, the code has to be hard-coded based on the specific provider type. To eliminate this inelegant implementation, in JDK6, the JDK provides java.util.ServiceLoader class. The configuration information in META-INF/ Services, coupled with the chain of responsibility pattern, provides a relatively reasonable solution for SPI loading.

The default context loader is the application classloader, so that the code in the startup classloader can also access the classes in the application classloader by mediating the above and below loaders.

The parental delegation mechanism is broken a third time

The third “break” of the parent delegate model is caused by the dynamic nature of the application pursued by users. For example, code Hot Swap, module Hot Deployment and so on

The key to implementing modular hot deployment in JSR-291(OSGIR4.2), led by IBM, is the implementation of its custom classloader mechanism. Each application module (called Bundle in OSGi) has its own classloader. When a Bundle needs to be replaced, The Bund1e is swapped out with the class loader to achieve hot replacement of the code. In the OSGi environment, classloaders no longer parent delegate the tree structure recommended by the model, but further evolve into a more complex network structure.

When a class load request is received, OSGi performs a class search in the following order:

$\color{red}{delegate a class starting with Java.* to the parent class loader. } $

$\color{red}{otherwise delegate the class in the delegate list to the parent class loader. } $

3) Otherwise, delegate the class in the Import list to the class loader of the Bundle that exported the class.

4) Otherwise, find the current Bundle’s ClassPath and load it using your own classloader.

5) Otherwise, find out if the class is in its own Fragment Bundle, and if so, delegate it to the Fragment Bundle’s class loader.

6) Otherwise, look for the Bundle in the Dynamic Import list and delegate it to the corresponding Bund1e class loader.

7) Otherwise, class lookup fails.

Note: Only the first two points still adhere to the principles of the parental delegate model; the rest of class lookup is done in the horizontal classloader

Summary: Here, we use the word “broken” to describe the above behavior that does not conform to the principles of the parental delegate model, but “broken” is not necessarily used in a pejorative sense. As long as there is a clear purpose and good reason, breaking through the old principles is undoubtedly a kind of innovation.

As: The OSGi class loader design does not conform to the traditional architecture of parents delegate class loader, and the industry in order to achieve to its hot deployment and extra high complexity of the dispute is not good, but for the technical personnel have to understand the basic or can reach a consensus, on the use of class loaders that OSGi is worth learning, Understanding the implementation of OSGi is the essence of class loaders.

5.4. Realization of hot replacement

Hot replacement refers to changing the behavior of a program by replacing its files without stopping the service during the program’s execution. $\color{red}{The key requirement for hot replacements is that the service cannot be interrupted and the changes must be immediately visible in the running system. }$Basically most scripting languages have built-in support for hot replacement, such as PHP. Once the PHP source file is replaced, the change takes effect immediately, without the need to restart the Web server.

But with Java, hot replacement is not inherently supported. If a class has already been loaded into the system, modifying the class file does not allow the system to reload and redefine the class. Therefore, one possible way to implement this functionality in Java is to flexibly use ClassLoader.

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

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



<hr/>

6. Sandbox security mechanism

Sandbox security mechanism

  • Ensure program security
  • Protect native Java JDK code

$\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 execution of a program.

The sandbox mechanism is to restrict Java code $\color{red}{to the specific running scope of the virtual machine (JVM) and severely restrict the code’s access to local system resources}$. This ensures limited isolation of code and prevents damage to the local system.

The sandbox mainly restricts access to system resources. What do system resources include? CPU, memory, file system, network. Different levels of sandboxes can also restrict access to these resources differently.

All Java program runs can specify the sandbox, can customize the security policy.

6.1. JDK1.0 period

Executing programs in Java are divided into native code and remote code, with the native code considered trustworthy by default and the remote code considered untrusted. For the native code granting credit, all local resources can be accessed. For non-trusted remote code, security in earlier Java implementations relied on the Sandbox mechanism. The JDK1.0 security model is shown in the figure below

6.2. JDK1.1 period

Such tight security in JDK1.0 also makes it difficult for applications to scale, such as when users want remote code to access files on the local system.

Therefore, in the subsequent Java1.1 version, the security mechanism has been improved, and the security policy has been added. Allows the user to specify code access to local resources.

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

6.3. JDK1.2 period

In Java1.2, security was improved again and code signatures were added. Regardless of the local code or the remote code, according to the user’s security policy Settings, the class loader will be loaded into the virtual machine with different permissions to achieve differentiated code execution permissions control. The JDK1.2 security model is shown in the figure below:

6.4. JDK1.6 period

The latest security mechanism implementation, the introduction of Domain (Domain) concept.

The virtual machine loads all the code into different system domains and application domains. $\color{red}{the system domain part is responsible for interacting with key resources}$, and the individual application domain parts are proxied by parts of the system domain to access the various required resources. Different Protected domains in a virtual machine have different permissions. Class files that exist in different domains have the full permissions of the current domain, as shown in the following figure. The latest security model (JDK1.6)



<hr/>

7. Loaders for custom classes

7.1. Why Custom Class Loaders?

  • $\color{red}{isolate load class}$

    In some frameworks, middleware is isolated from application modules and classes are loaded into different environments. For example, a container framework in Ari uses custom classloaders to ensure that the JARs an application depends on do not affect the JARs used by the middleware runtime. Another example is a Web application server such as Tomcat, which has several types of internal custom loaders to isolate different applications on the same Web application server.

  • $\color{red}{Modify how classes are loaded}$

    The class loading model is not mandatory. Except Bootstrap, other loading is not necessary to be introduced, or dynamic loading can be carried out on demand at a certain time point according to the actual situation

  • $\color{red}{extension load source}$

    Such as loading from a database, network, or even a TV set-top box

  • $\color{red}{prevent source code leak}$

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

Common Scenario

  • To achieve a similar in-process isolation, the classloader is actually used as a different namespace to provide a container-like, modular effect. For example, two modules that depend on different versions of a library can be loaded from different containers without interfering with each other. The integrators of this aspect are JavaEE, OSGi, JPMS and other frameworks.
  • Applications need to get class definition information from a different data source, such as a network data source, rather than the local file system. Or you need to manipulate the bytecode and dynamically modify or generate the type yourself.

Pay attention to

In general, using different classloaders to load different functional modules will improve the security of the application. However, when Java type conversions are involved, the loader is prone to nasty things. In Java type conversions, two types can only be cast if they are both loaded by the same loader, otherwise an exception will occur during the conversion.

7.2. Implementation Mode

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

There are two common ways to customize ClassLoader subclasses:

  • Option 1: Override the loadClass() method
  • Option 2: Override the findClass () method

contrast

  • These two methods are essentially the same, after all, loadClass() calls findClass(), but logically it is best not to modify the internal logic of loadClass() directly. The recommended approach is to simply override the custom Class loading method in findClass(), specifying the name of the Class as an argument, and returning a reference to the corresponding Class object.
  • The loadClass () method is where the parental delegate model logic is implemented, and tampering with this method can cause the model to break and cause problems. $\color{red}{so it is best to make small changes within the parental delegate model framework without breaking the old stable structure}$. It also avoids having to write duplicate code for parent delegates in the process of overwriting the loadClass() method yourself, which is always a better choice in terms of code reusability than modifying the method directly.
  • Once you have written your custom classloader, you can call the loadClass() method in your program to perform the class loading operation.

instructions

  • Its parent class loader is the system class loader
  • All class loading in the JVM will use Java. Lang. This. The loadClass (String) interface (custom class loaders and rewrite the Java. Lang. This. The loadClass (String) except the interface), Even the core class libraries of the JDK are no exception.

<hr/>

8. New features in Java9

In order to ensure compatibility, JDK9 does not radically change the three-tier classloader architecture or the parental delegate model, but there are still some noteworthy changes to make the modularized system work.

  1. The extension mechanism was removed, and the extension classloader was retained for backward compatibility reasons, but renamed to the Platform Class Loader. This can be obtained through the classLoader’s new method getPlatformClassLoader().

    JDK9 was built based on modularity (the original rt.jar and tools.jar were split into dozens of JMOD files), and the Java libraries were naturally extensible, so there was no need to keep the <JAVA_HOME >lib \ext directory. The previous mechanism of using this directory or java.ext.dirs system variables to extend JDK functionality is no longer of value.

  2. The platform class loader and the application class loader no longer inherit from the java.net.urlClassLoader.

    Now start the class loader, platform class loaders, all application class loader inheritance in JDK. Internal. Loader. BuiltinClassLoader.

If a program relies directly on this inheritance, or on a particular method of the URLClassLoader class, the code is likely to crash in JDK9 and later.

  1. In Java9, class loaders have names. 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 problems related to the class loader.
  2. The BootClassLoader is now a class loader implemented within the JVM in collaboration with the Java class libraries (formerly C++ implementation), but for compatibility with the previous code, null is still returned in the case of getting the BootClassLoader instead of getting the BootClassLoader instance.
  3. The delegate relationship for class loading has also changed. When a platform or application class loader receives a class load request, it first determines whether the class can be assigned to a system module before delegating it to the parent loader. If such a class can be assigned, it first delegates the class to the loader responsible for that module to complete the loading.

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. The println (this) getSystemClassLoader ()); / / get the platform class loader System. Out. The println (this) getPlatformClassLoader ()); / / the name of the access class loader System. Out. The println (ClassLoaderTest. Class. GetClassLoader (). The getName ()); }}