JVM (2)-Class Loading Mechanism-Principle of Parental Delegation

The loading subsystem of the class was introduced earlier. From a .class file to a class usable by the Java virtual machine, it must be loaded -> link (verification -> preparation -> analysis) -> initialization -> use -> unload these five Process, after these five processes, the .class file becomes a usable class, but specific to the component, who is performing the above five processes? Who guarantees the safety and accuracy of this loading process? Here we have to mention the class loader and the parent delegation model

One, the class loader ClassLoader

From the perspective of the virtual machine, there are two kinds of class loaders,①Start the class loader, ②Other loaderThe basis for this division is that the startup class loader is written in C/C++, and the other loaders are written in the Java language. But this division is too general.

From the perspective of Java developers, ClassLoader is divided into two categories:①The loader that comes with the virtual machine, ②User-defined class loader

Loader that comes with the virtual machine

1.BootStrap ClassLoader

BootStrap ClassLoader startup class loader, the startup class loader has the following characteristics:

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

  • It is used to load the core java library (JAVA_HOME/jre/lib/rt.jar/resources.jar or the content under the sun.boot.class.path path), and is used to provide the classes needed by the JVM itself

  • Does not inherit from java.lang.ClassLoader, there is no parent loader

  • Load extension classes and application class loader, and designate them as their parent loader

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

2. Extension ClassLoader

Extension ClassLoader expand the class loader

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

  • Derived 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 (extension directory) 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 extended class loader

3.AppClassLoader

AppClassLoader , the application class loader

  • Written in java language and implemented by sun.misc.Launcher$AppClassLoader.
  • Derived 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

This class loader is the default class loader in the program . Generally speaking, java application classes are loaded by it

The class loader can be obtained through the ClassLoader#getSystemClassLoader() method

/**
 * @author 四五又十
 * @version 1.0
 * @date 2020/7/4 9:46
 */
public class demo2 {
    
    
    public static void main(String[] args) {
    
    

        //应用程序加载器  sun.misc.Launcher$AppClassLoader@18b4aac2
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);

        //扩展类加载器  sun.misc.Launcher$ExtClassLoader@1540e19d
        ClassLoader exClassLoader = systemClassLoader.getParent();
        System.out.println(exClassLoader);

        //试图获取引导类加载器  null
        ClassLoader bootstrapClassLoader = exClassLoader.getParent();
        System.out.println(bootstrapClassLoader);
    }
}

Through the above program, it can be found that the value obtained by the bootstrap class loader Bootstrap ClassLoader is null, which is easy to understand, because the Bootstrap ClassLoader is written in C/C++ language, so it is naturally not available. It can also be found from the above program that there is a hierarchical relationship between Bootstrap ClassLoader, Extension ClassLoader, and AppClassLoader

The characteristics of these 3 loaders are introduced above. In fact, the main difference between these 3 loaders is that,Load different classes separately:

AppClassLoader : Responsible for loading user-written classes

Extension ClassLoader : Responsible for loading the classes in the <Java_Home>\lib\ext directory

BootStrap ClassLoader : Responsible for loading Java core class libraries, BootStrap startup class loader only loads classes whose package names start with java, javax, sun, etc.

For example: try to get the class loader that loads the String class: String class is loaded by BootStrap ClassLoader , then the output is null

//输出 null
ClassLoader classLoader = String.class.getClassLoader();
System.out.println(classLoader);

Method to obtain ClassLoader:

1. Get the ClassLoader of the current class: clazz.getClassLoader

2. Get the ClassLoader of the current thread: Thread.currentThread().getContextCladdLoader()

3. Get the classLoader of the system: ClassLoader.getSystemClassLoader()

4. Get the caller's classLoader: DriverManager.getCallerClassLoader()

4. User-defined loader

  • Load class in isolation
  • Modify the way the class is loaded
  • Expand loading source
  • Prevent source code leakage

2. Parental delegation mechanism

An example is used to illustrate the benefits of the parent delegation mechanism. For example, create a class in the working directory with the class name and package name: java.lang.String. There is no need to question here. Some people will ask that the String class is not included in Java. The class? This creation is legal, and the compiler will not report an error. In the String class, we just output a statement such as:

package java.lang;

/**
 * @author 四五又十
 * @version 1.0
 * @date 2020/7/6 18:29
 */
public class String {
    
    
    static {
    
    
        System.out.println("自定义String类");
    }
}

Then go to new a String in a main method

public class demo4 {
    
    
    public static void main(String[] args) {
    
    
        String s = new String();
    }
}

Thinking about it now, will the loading of the String class load the String in the jdk, or our custom String method, after all, they are all in the java.lang package? If it is to load the String class under jdk, the console will not output. If it is to load the custom String, because the static code block is used in the custom String class, the console must output a sentence "Custom String class"?

The answer is that the console does not output! ! That is, the Java virtual machine chooses to load the String in jdk, which is the role of the parent delegation model

The working process of the parent delegation mechanism is: if a class loader receives a request to load a class, it will not try to load the class by itself, but will pass the request to the parent class loader, which cannot be loaded in It is handed over to the parent class loader at a higher level, recursively in turn, and only when the parent class loader cannot load the class, the child loader will try to load it.

According to the parent delegation model, the process of loading demo4 as above can be drawn: the class loader receives the request to load demo4, then the virtual machine gives the class to the parent loader Extension ClassLoader , and I can’t load this class when I look at the Extension ClassLoader . Then give it to the parent class loader BootStrap ClassLoader , BootStrap ClassLoader can’t be loaded, so it’s still delegated until AppClassLoader , AppClassLoader is responsible for loading user-defined classes, it can be loaded, then demo4 is loaded into the virtual machine Up.

Look at the loading process of the String class, first AppClassLoader received a request to load the String class, AppClassLoader he will not try to load, to be handed over to the parent Extension ClassLoader , Extension ClassLoader a look I did not have permission to load, then appoint up post in For BootStrap ClassLoader , BootStrap ClassLoader sees that String is under the java package. Loading this class belongs to the work of BootStrap ClassLoader. Then the Stirng class is loaded on the virtual machine. Then since the String class is loaded by BootStrap ClassLoader, then obviously Is String in jdk

In the source code, the code to implement the parent delegation mechanism is in the loadClass method of java.lang.ClassLoader:

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
    
    
        synchronized (getClassLoadingLock(name)) {
    
    
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
    
    
                long t0 = System.nanoTime();
                try {
    
    
                    if (parent != null) {
    
    
                        c = parent.loadClass(name, false);
                    } else {
    
    
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
    
    
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
    
    
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
    
    
                resolveClass(c);
            }
            return c;
        }
    }

2.1 Benefits of the parental delegation model

  • The priority hierarchical relationship stipulated by the parent delegation model can avoid repeated loading of classes. When the parent loader has already loaded this class, if there is another request to load this class, then the application class loader will hand the 1 request to the parent class loader, and then BootStrap starts the class loader to execute the findLoadedClass method, and find The class has already been loaded, it will directly return that the class is not being loaded, which avoids repeated loading of the class
  • Another advantage of the parent delegation model is that it prevents the core classes from being modified. From the above example, you can know that the general core classes refer to some classes in the rt.jar or tools.jar package. If this class is maliciously modified, then Unintended consequences will occur, and this kind of parental delegation model load class hierarchy ensures that the core class is loaded, because the startup class only loads the classes under the correct path

2.2 Breaking the parental delegation model

The parental delegation model ensures that the basic classes of each class loader are consistent, that is, these basic classes are handed over to the upper class loader for loading, but this also brings a problem. There are many service core calling interfaces (SPI for short) in Java applications. These interfaces allow third parties to implement it, such as JDBC, etc. These SPI interfaces belong to the core class library and should be handed over to the BootStrap startup class loader for loading. However, the problem arises that the implementation classes of these interfaces are third-party interfaces. From the above, we know that third-party libraries should be handed over to the application loader AppClassLoader for loading. Due to the existence of parental delegation, Bootstrap cannot delegate AppClassLoader to load these SPI implementation classes

There are many service core calling interfaces (SPI for short) in the application. These interfaces allow third parties to implement it, such as JDBC, etc. These SPI interfaces belong to the core class library and should be loaded by the BootStrap startup class loader, but the problem The implementation classes that appear in these interfaces are third-party interfaces. From the above, we know that third-party libraries should be handed over to the application loader AppClassLoader for loading. Due to the existence of parental delegation, Bootstrap cannot delegate AppClassLoader to load these SPI implementation classes.

To solve this problem, it is necessary to introduce some special third-party loaders, and the thread context class loader is such a class loader that breaks the parent delegation mechanism. The thread context loader is introduced, and the program can be started by The classes loaded by the class loader are loaded by the custom loader, which realizes that the parent class loader entrusts the sub-class loader to load the class, which solves the problem that the parent class cannot delegate the sub-class loading under the parent delegation mechanism

Guess you like

Origin blog.csdn.net/weixin_44706647/article/details/115140343