Chapter 2: Class loading mechanism — parent delegation model

1, the introduction of

The Java virtual machine loads class files on demand, which means that it loads its class files into memory to generate class objects when the class is needed. In addition, when loading a class file, the Java VIRTUAL machine adopts the parental delegation mode, that is, the request to the parent class processing, which is a kind of task delegation mode.

For example, we now have this problem: create a custom java.lang package and try to write a custom String that has the same name as an existing class in the rt.jar library

package java.lang;
    
public class String {
	// During initialization, when the class is loaded, the static code block is loaded
	static{
   		System.out.println( "I'm a static block of custom String class.")}}Copy the code

Then, create a program under another normal package

package com.atguigu.java1;
    
public class StringTest{
   public static void main(String[] args){
      String str = new String();// Parent delegate mode loads the String class
      System.out.println("hello")}}Copy the code

Result: You’ll find that the custom String class compiles normally, but does not load and run. Execute the StringTest program and output “hello”. It does not output the static code block of the String class in the custom lang package. The result shows that the new String class is the java.lang of the core API. The JDK’s native String class is still loaded, not our custom String class. This is where the parent delegate mechanism comes in, and if it’s really custom, the program is very risky because it can be changed and injected at will.

2. Working principle

  • If a classloader receives a classload request, it does not load the request itself. Instead, it delegates the request to the parent class’s loader.
  • If the parent class loader also has its parent class loader, then further delegate up, recursively, the request will eventually reach the top level of the start class loader;
  • If the parent class loader can complete the task, it returns successfully. If the parent class loader cannot complete the task, the child loader will try to load itself. This is the parent delegate mode.

Let’s use the String example above to illustrate:

Loading StringTest this class, we need to load a String class – this class, due to our custom a String class, it should be morally by the system class loader loads, but because parents delegate mechanism, when the custom class loader received the system class loader 】 【 class loading request, it will not go to loading, Instead, it delegates up to the bootstrap class loader, and since the bootstrap class loader itself loads classes from packages that start with Java, etc., this String is a class from a java.lang package that starts with java.lang, so it doesn’t delegate down. So prove that the new String class in the inner core API is the java.lang, not custom.

What if that’s the case?

StringTest strtest = new StringTest();
Copy the code

Principle is still the same, when the StringTest custom class loader received the system class loader 】 【 class loading request, it will not go to loading, but has been entrusted to guide the class loader upwards, but the bootstrap class loader can’t handle, will entrust down, has been entrusted to the system class loader to deal with, So this StringTest class is loaded by the system class loader

Let’s look at another program [defined under the custom java.lang package]

package java. lang;
public class String {
    // During initialization, when the class is loaded, the static code block is loaded
    static{
        System.out.println("I'm a static block of custom String class.");
    }
    public static void main(String[] args) {
        System.out.println("hello"); }}Copy the code

Results:

Error: Main method not found in java.lang.String class. Define main as:public static void main(String[] args)Otherwise deployment headaches the application class must extend deployment headaches. Application. The applicationCopy the code

The reason: Because we want to execute main, the String class that’s in main should be loaded, but since the String class is ultimately handed over to the bootloader, which executes main after it’s loaded, because the bootloader itself loads the Java core API libraries, In the core API, String does not have a main method at all. If we ignore the information in the String class, we will get an error.

3. Example of parent delegation mechanism

Jar is implemented based on the SPI interface, so at load time, the parent delegate will be done. Finally, the SPI core class will be loaded from the boot class loader, then the SPI interface class will be loaded, and then the reverse delegate will be done. The implementation class jdbc.jar is loaded through the thread context class loader.

4. Advantages of parent delegation

The parent delegation model, introduced in JDK1.2, is not a mandatory model, but rather a best practice for a loader implementation mechanism that Java designers recommend to developers. From the example above, we can see that the parental mechanism can

  • Avoid class reloading: Prevent the same.class from being reloaded. You can ask the delegate up there, so once it’s loaded, you don’t have to load it again. Ensure data security.

  • Protect program security from arbitrary tampering with the core API: ensure that the core. Class cannot be tampered with. By delegating, you don’t tamper with the core Java.class, and even if you do, you don’t load it, and even if you load it, it won’t be the same.class object. Different loaders do not load the same.class object. This ensures Class execution security.

    • Custom class: java.lang.string
      • Custom class: java.lang.ShkStart (error: prevents creation of java.lang classes)
package java.lang;
public class ShkStart {
    public static void main(String[] args) { 
        System.out.println("hello!"); }}Copy the code

The java.lang package does not allow us to customize classes

5. Why design this mechanism

The nice thing about this design is that if someone wants to replace system-level classes, such as String.java, and tamper with their implementation, those system-level classes have already been loaded by the Bootstrap classLoader under this parental delegation mechanism (why? Since BootstrapClassLoader is the first thing to try to load a class when it needs to be loaded, other classloaders do not have a chance to load it, preventing dangerous code to some extent.

The “parent delegation model” ensures the security of classes at the system level, keeping some of the base classes from being corrupted by developer customization.

Instead of using the parent delegate model, each class loader loads it by itself. If a developer writes a class called java.lang.String and places it in the program’s ClassPath, the system will have multiple String classes, and the most basic behavior of the Java type system will not be guaranteed. Applications will also become chaotic.

6. Sandbox safety mechanism

Lenovo 360 sandbox security mechanism

The core of the Java security model is the Java sandbox. What is a sandbox?

The sandbox is an environment that restricts the execution of programs. The sandbox mechanism ensures effective code isolation by limiting Java code to a specific running scope of the VIRTUAL machine (JVM) and strictly limiting code access to local system resources. Sandboxes mainly restrict access to system resources. What do system resources include? — CPU, memory, file system, network. Different levels of sandboxes can limit access to these resources differently.

Java \lang\String. jar: java.lang \ string. jar: java.lang \ string. jar: java.lang \ string. jar: java.lang \ string. jar: java.lang \ string. jar: java.lang \ string. jar: java.lang \ string. jar: java.lang \ string. jar: java.lang \ string. jar: java.lang \ string. jar: java.lang \ string. This is because the string class is loaded in the rt.jar package. This ensures the protection of Java core source code, which is an embodiment of sandbox security mechanism.

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

  1. Start with a bytecode validator: Ensuring that Java class files follow the Java language specification helps Java programs achieve memory protection, but not all class files are bytecode validators, such as core classes.
  2. Next up is the classloader: the classloader works with the Java sandbox in three ways: it prevents malicious code from interfering with well-meaning code, and it guards trusted library boundaries. It classifies code into protected domains and determines what it can do.
  3. The virtual machine provides different namespaces for classes loaded by different class loaders. The namespace consists of a series of unique names. Each loaded class will have a name. The mechanism used by class loaders is the parent delegate pattern.

Active and passive use of classes

7.1. How do I determine whether two class objects are the same

There are two requirements to indicate whether two class objects are the same class in the JVM:

  • The full class name of the class must be consistent, including the package name.
  • The ClassLoader (ClassLoader instance object) that loads this class must be the same.

In other words, in the JVM, even if these two class objects come from the same class file and are loaded by the same virtual machine, they are not equal as long as the ClassLoader instance objects that loaded them are different.

7.2. References to class loaders

The JVM must know whether a type is loaded by the boot loader or by the user class loader. If a type is loaded by a user class loader, the JVM stores a reference to that class loader in the method area as part of the type information. When resolving a reference from one type to another, the JVM needs to ensure that the classloaders for the two types are the same.

7.3. Active and passive use of classes

Java programs use classes in active and passive ways.

Active use, and divided into seven cases:

  • Create an instance of the class
  • Accesses or assigns a value to a static variable of a class or interface
  • Call a static method of a class
  • Reflection (e.g. Class.forname (” com.atguigu.test “))
  • Initialize a subclass of a class
  • Classes that are identified as startup classes when the Java virtual machine starts
  • Dynamic language support for the beginning of JDK7:
  • Java. Lang. Invoke. MethodHandle instance analytical results of REF getStatic, REF putStatic, REF invokeStatic handle corresponding class does not initialize, is initialized

Except for these seven cases, any other way of using A Java class is considered a passive use of the class and does not result in class initialization.

Refer to chapter 1 for details:

8. Break the parental delegation model

8.1 Code implementation of parental delegation model

The parent delegate model is very important for the stable running of Java programs, but its implementation is simple. The code implementation of the parent delegate model is concentrated in the loadClass() method of java.lang.classLoader. The code logic is as follows:

  1. First check if the class is loaded. If not, the loadClass() method of the parent class loader is called.
  2. If the parent class loader is empty, the startup class loader is used as the parent by default.
  3. If the parent class fails to load, throw a ClassNotFoundException and then call your own findClass() method to try to load.

LoadClass method source code is as follows:

protected synchronizedClass<? > loadClass(String name,boolean resolve) throws Clas sNotFoundException{
    //1 first checks if the class is loaded
    Class c = findLoadedClass(name);
    if (c ==null) {
        try {
            if(parent ! =null) {
                //2 If not, call the parent loadClass() method;
                c = parent.loadClass(name,false);
            } else
                //3 If the parent class loader is empty, the parent class loader is used by default.c = findBootstrapClass0(name); }}catch (ClassNotFoundException e) {
        // if the parent class fails to load, throw ClassNotFoundException
    }
    if(c==nul1){
        //5 The parent class loader cannot complete the loading request, and then calls its own f indClass() method to load the class
        c = findClass(name);
    }
    if (resolve) {
        resolveClass(c);
    }
    return c;
}
Copy the code

8.2. Destroy the parental delegation model

As mentioned earlier, the parental delegation model is not a mandatory constraint model, but rather a recommended implementation of class loaders by Java designers to developers. Most class loaders in the Java world follow this model, but there are exceptions, and so far the parent delegate model has mostly been “broken” on three large scales. 【 Details 】

9,

The parent delegate model requires that all class loaders have their own parent class loaders, except for the top-level start class loaders. However, the relationship between class loaders is not generally implemented as an inherited relationship, but rather a combinative relationship is often used to duplicate the parent loader’s code.

For any class, its uniqueness in the virtual machine needs to be established by both the classloader that loads it and the class itself. Each classloader has a separate class namespace. Thus, using the parent-delegate model to organize relationships between class loaders has an obvious benefit: a class has a hierarchical relationship with priority along with its class loaders:

An example is the java.lang.Object class, which is stored in rt.jar and loaded by the boot class loader. The parental delegation model ensures that any loading request to java.lang.Object received by a class loader is ultimately delegated to the starting class loader at the top of the model, so that the Object class is the same class in the various classloader environments of the program.

On the other hand, if a user writes a class called java.lang.Object and loads it with a custom class loader, the system will have multiple Object classes and the basic behavior of the Java type system will not be guaranteed. Applications will also become chaotic. Like the user-defined String class above