In-depth understanding of the parent delegation mechanism

1. What is the parental delegation mechanism

When a certain class loader needs to load a certain .class file, it first delegates this task to its superior class loader. This operation is recursive. If the superior class loader does not load it, it will load the class itself.

Insert picture description here

2. Class Loader
  • BootstrapClassLoader (startup class loader)
    written in c++, loading the java core library java.*, constructing ExtClassLoader and AppClassLoader. Since the boot class loader involves the local implementation details of the virtual machine, developers cannot directly obtain a reference to the startup class loader, so direct operations by reference are not allowed.

  • ExtClassLoader (standard extended class loader)
    Write in java, load the extended library, such as jre in the classpath, javax.* or java.ext.dir in the specified location, developers can directly use the standard extended class loader.

  • AppClassLoader (system class loader)
    written in java, the directory where the loader is located, such as the class where user.dir is located

  • CustomClassLoader (user-defined class loader)
    written in java, user-defined class loader, can load the class file of the specified path

3. The loading path of the class loader
import java.net.URL;
import java.net.URLClassLoader;
 
/*
分析BootstrapClassLoader/ExtClassLoader/AppClassLoader的加载路径
*
*/
public class ClassPath_of_Bootstrap_Ext_AppClassLoader {
 
    public static void main(String[] args) {
        System.out.println("BootstrapClassLoader 的加载路径: ");
        URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
        for (URL url : urls) {
            System.out.println(url);
        }
        System.out.println("----------------------------");
 
        //取得扩展类加载器
        URLClassLoader extClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader().getParent();
        System.out.println(extClassLoader);
        System.out.println("扩展类加载器 的加载路径: ");
        urls = extClassLoader.getURLs();
        for (URL url : urls) {
            System.out.println(url);
        }
        System.out.println("----------------------------");
 
 
        //取得应用(系统)类加载器
        URLClassLoader appClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        System.out.println(appClassLoader);
        System.out.println("应用(系统)类加载器 的加载路径: ");
        urls = appClassLoader.getURLs();
        for (URL url : urls) {
            System.out.println(url);
        }
        System.out.println("----------------------------");
    }
}

Insert picture description here
Insert picture description here

  • BootstrapClassLoader startup class loader-load the core library in the jre/ directory
  • ExtClassLoader extended class loader-load the extension package in the /jre/lib/ext/ directory
  • AppClassLoader application (system) class loader-load the package under the classpath path
4. Understanding the source code
protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 首先检查这个classsh是否已经加载过了
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    // c==null表示没有加载,如果有父类的加载器则让父类加载器加载
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        //如果父类的加载器为空 则说明递归到bootStrapClassloader了
                        //bootStrapClassloader比较特殊无法通过get获取
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {}
                if (c == null) {
                    //如果bootstrapClassLoader 仍然没有加载过,则递归回来,尝试自己去加载class
                    long t1 = System.nanoTime();
                    c = findClass(name);
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
1. Flow chart

Insert picture description here

2. Process

First determine whether the class has been loaded.
If it is not loaded, it is passed to the parent loader to load it,
if the parent loader fails to load it, it uses findClass() to load it by itself. So it is an upward recursive process.
Custom When loading the loader, you need to rewrite the findClass method because it is empty and has no content:

5. The role of the parental delegation mechanism
1. Ensure safety

Prevent the same .class from being loaded repeatedly. Ask the above by entrusting. Once loaded, there is no need to load it again. Ensure data security.

2. Guarantee uniqueness

Ensure that the core .class cannot be tampered with. Through the delegation method, the core .clas will not be tampered with, even if tampered, it will not be loaded, and even if it is loaded, it will not be the same .class object. Different loaders load the same .class and not the same Class object. This ensures the safety of Class execution.

Just imagine, if there is no parent delegation model but loaded by each class loader, if the user writes a java.lang.Object class with the same name and puts it in the ClassPath, multiple class loaders will load this class into memory , There will be multiple different Object classes in the system, so the comparison result between the classes and the uniqueness of the classes will not be guaranteed, because the Objects are all different, then the program will run and start errors, and it will also ensure that the JVM can be normal safe operation.

Guess you like

Origin blog.csdn.net/qq_43141726/article/details/114373312