Java class loading mechanism-parent delegation mechanism

I recently learned Java's low-level class loading mechanism and summarized it. If there is anything wrong, please correct me!


1. Three loaders built into Java

Boot class loader: The bottom layer of this loader is implemented by C++ code, and its main function is to load java core class libraries, such as java.lang.
Extended class loader: The loader is mainly implemented by Java code, so you can track related codes through idea (the IED tool that the author mainly uses). The function of the loader is to load related class libraries in the ext extension directory under the lib directory of the JRE.
Application loader: The loader is the same as the extended class loader, and the bottom layer is implemented by Java code. It is mainly responsible for loading user-defined classes under the classpath (classPath).

Java's parent delegation mechanism is implemented by calling each other between the above three classes (the loader is actually a class)

2. Parental delegation mechanism

The parent delegation mechanism is actually not complicated. In fact, the subclass (application loader) queries whether the class that needs to be loaded has been loaded in the loading area managed by it , and if not, the parent class (extended class loader) is required to check. Then if the parent class (extended class loader) is not found, let the grandparent class (boot class loader) look for it. Then the grandparent class (boot class loader) will go to the corresponding class path to find the specific class file to load if it is not found in the loading area . If the grandparent class (the boot class loader) is not found in the classpath managed by the parent class (the extended class loader), the parent class (extended class loader) will be arranged to search for the classpath managed by its lock. If it is still not found, let the subclass (application The program loader) goes to the class path managed by itself to search, if it still does not find it, it will report an exception.

In fact, it’s just a round-trip path to find something. If you don’t find something in your home, then you go to your dad’s house. Then if you haven’t found it, you go to your grandfather’s house and you haven’t found it. Then your grandpa remembers He seemed to put the writing in the bank safe, and then he went to get it back. After you read it again, and found that there is still no, you asked your dad to go to the bank safe to look for it, but there is still no, and finally go to your own Look in the bank safe. (It doesn't matter if you find it or not, this set of back and forth constitutes a parent delegation mechanism)
Insert picture description here
Note: The three loaders are not inherited from each other, but only call each other.

Third, the advantages of the parental delegation mechanism

  • Sandbox security mechanism: The parental delegation mechanism ensures that the core of the Java core class library will not be replaced by user-defined classes, and can prevent the core API from being altered at will.
  • Avoid repeated loading of classes: when the parent class loads the class that needs to be loaded, the subclass will not be loaded again, ensuring the uniqueness of the loaded class.

4. Break the parental delegation mechanism

1. Why break the parental delegation mechanism?

Although the parental delegation mechanism has many advantages, it is not suitable for some special needs. For example, when running web applications with different versions of spring in Tomcat, due to some subtle differences in the class libraries of different versions, and the class names and method names in the two class libraries are roughly the same, it is necessary to load two different class libraries to To meet the demand, it is necessary to break the parental delegation mechanism.

2. Break the principle of the parental delegation mechanism

Mainly by customizing the loader, rewriting the loadClass method in the ClassLoader class to break the parent delegation mechanism.

3. How to customize the loader?

A custom loader needs to inherit the ClassLoader class and override the findClass method. The findClass method is mainly used to read the class file in the corresponding path and convert it into an object in the JVM. So this step cannot be omitted .

The following code is the specific implementation of the findClass method, for reference only

private byte[] loadByte(String name) throws Exception {
    
    
    name = name.replaceAll("\\.", "/");
    FileInputStream fis = new FileInputStream(classPath + "/" + name + ".class");
    int len = fis.available();
    byte[] data = new byte[len];
    fis.read(data);
    fis.close();
    return data;
}

protected Class<?> findClass(String name) throws ClassNotFoundException {
    
    
    try {
    
    
        byte[] data = loadByte(name);
        //defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节 数组。
        return defineClass(name, data, 0, data.length);
    } catch (Exception e) {
    
    
        e.printStackTrace();
        throw new ClassNotFoundException();
    }
}

4. Rewrite the loadClass method to break the parent delegation mechanism

/**
 * 重写类加载方法,实现自己的加载逻辑,不委派给双亲加载
 * @param name
 * @param resolve
 * @return
 * @throws ClassNotFoundException
 */
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) {
    
    
            // If still not found, then invoke findClass in order
            // to find the class.
            long t1 = System.nanoTime();
            //用于过滤出需要打破双亲委派机制进行加载的类包
            if(!name.startsWith("com.muyichen.jvm")){
    
    
                // 注意这里需要给c赋值。。。
                c = this.getParent().loadClass(name);
            }else{
    
    
                c = findClass(name);
            }
            // this is the defining class loader; record the stats
            sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
            sun.misc.PerfCounter.getFindClasses().increment();
        }
        if (resolve) {
    
    
            resolveClass(c);
        }
        return c;
    }
}

Guess you like

Origin blog.csdn.net/qq_42697271/article/details/114074750