java class loader

java. java is often encountered in the development process Lang. classnotfoundexception. Why is this exception? Because the class you want to use is not loaded into the virtual machine. This article will introduce the class loader of java, let you understand the mechanism of loading a class file into the virtual machine, and introduce how to customize the class loader. Combined with code verification theory.

JVM predefined three kinds of Loaders

The JVM predefines three types of loaders:

  • Boot class loader (BootStrap)
  • Extension class loader
  • System class loader (system)

Start class loader

The startup class loader is implemented using local code, which is similar to the native method when we look at the source code. We can't find a specific class. It loads Java_ Load the core class library under home / lib or the jar under the path specified by the - Xbootclasspath option into the virtual machine.

System. The getproperty ("sun.boot.class.path") parameter allows you to view the path loaded by the class loader.

Because there is no specific class, you can't see the class diagram.

extensions class loader

The extension class loader is sun misc. Launcher$ExtClassLoader. It is responsible for JAVA_HOME /lib/ext or by the system variable - DJava Ext.dir loads the class library in the specified location into memory.

System. The getproperty ("java.ext.dirs") parameter allows you to view the path loaded by the class loader.

Class diagram is as follows:

It's sun misc. Inner class of launcher.

system class loader

The system class loader is sun misc. Launcher$AppClassLoader. It is responsible for loading the directory indicated by the user class path (Java) - classpath or - Djava.class.path variable, that is, the class library under the path of the current class and its referenced third-party class library into memory. Developers can directly use the system class loader.

System.getProperty("java.class.path") to view the path loaded by the class loader.

Class diagram is as follows:

Like the extension class loader, it is also sun misc. Inner class of launcher.

Three kinds of loaded file path test code

The following code prints the jar packages of which paths are loaded by the three kinds of loaders to verify the above introduction

package ClassLoader;

/**
 * @author ludengke
 * @title: ClassLoader.TestClassLoader
 * @projectName springcloud-demo
 * @description: TODO
 * @date 2021/12/2615:15
 */
public class TestClassLoader {

    public static void main(String[] args) {
        bootStrapClassLoader();
        extClassLoader();
        appClassLoader();
//        testClassLoader();
    }

    /**
     * Test which class loader TestBean is loaded by and what is the loading path of this loader
     */
//    private static void testClassLoader(){
//        try {
//            //View the path entries contained in the current system classpath
//            System.out.println(System.getProperty("java.class.path"));
//            //Call the class loader that loads the current class (here, the system class loader) to load the TestBean
//            Class typeLoaded = Class.forName("sun.net.spi.nameservice.dns.DNSNameService");
//            Class typeLoaded2 = Class.forName("ClassLoader.TestBean");
//            //See which type of TestBean is loaded by which class loader
//            System.out.println(typeLoaded.getClassLoader());
//            System.out.println(typeLoaded2.getClassLoader());
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }
    /***
    *@Description Test the path of bootstrap load
    *@Param []
    *@Return void
    *@Author ludengke
    *@Date 2021/12/26
    *@Time 15:17
    */
    private static void bootStrapClassLoader(){
        System.out.println("bootstrap start:");
        System.out.println(System.getProperty("sun.boot.class.path"));
        System.out.println("bootstrap end:");

    }
    /***
    *@Description extClassLoader Loaded path
    *@Param []
    *@Return void
    *@Author ludengke
    *@Date 2021/12/26
    *@Time 15:26
    */
    private static void extClassLoader(){
        //testClassLoaderParent();
        System.out.println("ext start");
        System.out.println(System.getProperty("java.ext.dirs"));
        System.out.println("ext end");

    }

    /**
     * Gets the parent of the class loader
     */
    private static void testClassLoaderParent(){
        System.out.println(ClassLoader.getSystemClassLoader());
        System.out.println(ClassLoader.getSystemClassLoader().getParent());
        System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
    }
    /**
    *@Description appClassLoader Loaded path
    *@Param []
    *@Return void
    *@Author ludengke
    *@Date 2021/12/26
    *@Time 15:29
    */
    private static void appClassLoader(){
        System.out.println("app start");
        System.out.println(System.getProperty("java.class.path"));
        System.out.println("app end");

    }
}

The execution results of the test class are as follows:

D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=54689:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\study\target\classes;D:\work\maven\mavenstore\org\openjdk\jol\jol-core\0.9\jol-core-0.9.jar ClassLoader.TestClassLoader
bootstrap start:
D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\java\jre\lib\sunrsasign.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\classes
bootstrap end:
ext start
D:\work\java\jre\lib\ext;C:\WINDOWS\Sun\Java\lib\ext
ext end
app start
D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\study\target\classes;D:\work\maven\mavenstore\org\openjdk\jol\jol-core\0.9\jol-core-0.9.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar
app end

Process finished with exit code 0

From the test results, we can see that the system class loader also loads the paths that should be loaded by the startup class loader and extension class loader. Is there a problem?
It should not. The class loading mechanism is described below.

Class loading mechanism (parental delegation mechanism)

The inheritance relationship of the class loader is as follows. The inheritance relationship here is not real inheritance, but the parent-child delegation relationship of the class loader

Parental delegation mechanism:

  • When the class loader receives a request to load a class, first check whether the class loader has loaded this class. If it has loaded this class, it does not need to be loaded and can be used directly. If it has not loaded this class, it is delegated to the parent class loader to load it.
  • And so on until BootStrapClassLoader.
  • If BootStrapClassLoader cannot load this class, it will be loaded by ExtClassLoader entrusted to its subclass.
  • And so on, up to the lowest class loader.
  • If you can't load it, you can't find the error of this class.

    Role of parental delegation mechanism:
    Why is it so designed?
    From this loading mechanism, we can see that the top-level class loader has much higher priority and will overwrite the classes loaded by the bottom-level class loader.
    When delegating to the parent class loader, if the parent class has loaded the class, it can be used directly without reloading, and it is guaranteed that the content loaded by the parent class loader will not be overwritten to ensure data security.
    The class loader on the upper layer can't be loaded and can't hold it. It can only be loaded by children and grandchildren themselves. Otherwise, the bottom loader is gone.
    To sum up, children are very lazy. If they have loaded this class, they can use it directly, otherwise they will ask their elders for it. If the elders don't have it, the children will load it by themselves.
  • Prevent repeated loading of the same class. Ask the above through the delegate. After loading, you don't have to load it again. Ensure data security.
  • Guarantee the core Class cannot be tampered with. By means of delegation, the core will not be tampered with clas, even if tampered, will not be loaded, even if loaded, it will not be the same Class object. Different loaders load the same Class is not the same class object. This ensures the security of class execution.

Test class loading mechanism

  • The test code is as follows
    Just write a class TestBean
package ClassLoader;

public class TestBean {
    public TestBean() {
    }
}

The test class mainly focuses on the testClassLoader() method

package ClassLoader;

/**
 * @author ludengke
 * @title: ClassLoader.TestClassLoader
 * @projectName springcloud-demo
 * @description: TODO
 * @date 2021/12/2615:15
 */
public class TestClassLoader {

    public static void main(String[] args) {
//        bootStrapClassLoader();
//        extClassLoader();
//        appClassLoader();
        testClassLoader();
    }

    /**
     * Test which class loader TestBean is loaded by and what is the loading path of this loader
     */
    private static void testClassLoader(){
        try {
            //View the path entries contained in the current system classpath
//            System.out.println(System.getProperty("java.class.path"));
            //Call the class loader that loads the current class (here, the system class loader) to load the TestBean
            Class typeLoaded = Class.forName("sun.net.spi.nameservice.dns.DNSNameService");
            Class typeLoaded2 = Class.forName("ClassLoader.TestBean");
            //See which type of TestBean is loaded by which class loader
            System.out.println(typeLoaded.getClassLoader());
            System.out.println(typeLoaded2.getClassLoader());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /***
    *@Description Test the path of bootstrap load
    *@Param []
    *@Return void
    *@Author ludengke
    *@Date 2021/12/26
    *@Time 15:17
    */
    private static void bootStrapClassLoader(){
        System.out.println("bootstrap start:");
        System.out.println(System.getProperty("sun.boot.class.path"));
        System.out.println("bootstrap end:");

    }
    /***
    *@Description extClassLoader Loaded path
    *@Param []
    *@Return void
    *@Author ludengke
    *@Date 2021/12/26
    *@Time 15:26
    */
    private static void extClassLoader(){
//        testClassLoaderParent();
        System.out.println("ext start");
        System.out.println(System.getProperty("java.ext.dirs"));
        System.out.println("ext end");

    }

    /**
     * Gets the parent of the class loader
     */
    private static void testClassLoaderParent(){
        System.out.println(ClassLoader.getSystemClassLoader());
        System.out.println(ClassLoader.getSystemClassLoader().getParent());
        System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
    }
    /**
    *@Description appClassLoader Loaded path
    *@Param []
    *@Return void
    *@Author ludengke
    *@Date 2021/12/26
    *@Time 15:29
    */
    private static void appClassLoader(){
        System.out.println("app start");
        System.out.println(System.getProperty("java.class.path"));
        System.out.println("app end");

    }
}

  • Run test class
sun.misc.Launcher$ExtClassLoader@7f31245a
sun.misc.Launcher$AppClassLoader@18b4aac2

Process finished with exit code 0
  • sun.net.spi.nameservice.dns.DNSNameService is a class in the path loaded by the extension class loader. I won't look at it for the time being. Mainly focus on classloader Testbean, this class is loaded with AppClassLoader, and the class written above is loaded.
  • Add classloader Testbean class generates testjar Jar, copy the jar package to Java_ Run again under home \ JRE \ lib \ ext, and the results are as follows. You can see that classloader Testbean class is loaded by ExtClassLoader class loader, and Java is loaded_ Contents of testjar under home \ JRE \ lib \ ext. The parental delegation mechanism can be verified.
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=62498:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\study\target\classes;D:\work\maven\mavenstore\org\openjdk\jol\jol-core\0.9\jol-core-0.9.jar ClassLoader.TestClassLoader
sun.misc.Launcher$ExtClassLoader@7f31245a
sun.misc.Launcher$ExtClassLoader@7f31245a

Process finished with exit code 0

  • Put testjar.jar Copy jar to Java_ Under home / lib, run the test class again, and the results are as follows. As a rule, starting the class loader should load testjar.jar Classloader. Jar Testbean, but no. Why? If you write everything inside, jdk is not safe, so things he doesn't know are not loaded to ensure safety.
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=62680:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\study\target\classes;D:\work\maven\mavenstore\org\openjdk\jol\jol-core\0.9\jol-core-0.9.jar ClassLoader.TestClassLoader
sun.misc.Launcher$ExtClassLoader@7f31245a
sun.misc.Launcher$ExtClassLoader@7f31245a

Process finished with exit code 0

Custom class loader

  • Write the loaded class and write any method in it. The code is as follows:
package ClassLoader;

public class TestBean {
    public TestBean() {

    }
    public void testMethod(){
        System.out.println("ClassLoader.TestBean.testMethod()");
    }
}

  • Write a custom class loader MyClassLoader and inherit Java Lang. classloader, override the findClass method, and the code is as follows:
package ClassLoader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * @author ludengke
 * @title: MyCloassLoader
 * @projectName springcloud-demo
 * @description: TODO
 * @date 2022/1/522:41
 */
public class MyCloassLoader extends ClassLoader {
    private String path;

    public MyCloassLoader(String path) {
        this.path = path;
    }

    /**
     * This method of the re parent class
     *
     * @param name
     * @return
     * @throws ClassNotFoundException
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class log = null;
        // Gets the bytecode array of the class file
        byte[] classData = getData();

        if (classData != null) {
            // Converts the bytecode array of class to an instance of class
            log = defineClass(name, classData, 0, classData.length);
        }
        return log;

    }

    /**
     * Gets the bytecode of the class file
     * @return
     */
    private byte[] getData() {
        File file = new File(path);
        if (file.exists()) {
            FileInputStream in = null;
            ByteArrayOutputStream out = null;
            try {
                in = new FileInputStream(file);
                out = new ByteArrayOutputStream();

                byte[] buffer = new byte[1024];
                int size = 0;
                while ((size = in.read(buffer)) != -1) {
                    out.write(buffer, 0, size);
                }

            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    in.close();
                } catch (IOException e) {

                    e.printStackTrace();
                }
            }
            return out.toByteArray();
        } else {
            return null;
        }
    }

}

  • Write the test class with the following code:
package ClassLoader;

import java.lang.reflect.Method;

/**
 * @author ludengke
 * @title: ClassLoader.TestClassLoader
 * @projectName springcloud-demo
 * @description: TODO
 * @date 2021/12/2615:15
 */
public class TestClassLoader {

    public static void main(String[] args) {
        testMyClassLoader();
    }

    /**
     * Test custom class loader
     */
    private static void testMyClassLoader(){
        try {
            //Instance class loader
            MyCloassLoader cloassLoader=new MyCloassLoader("D:\\work\\springcloud-demo\\study\\target\\classes\\ClassLoader\\TestBean.class");
            System.out.println("The parent class loader of the custom class loader is:"+cloassLoader.getParent());
            //Load classes through a custom class loader
            Class testBeanClass=cloassLoader.findClass("ClassLoader.TestBean");
            //Class loader of the loaded class
            System.out.println("Class loader is:" + testBeanClass.getClassLoader());
            //Calling methods of a class through reflection
            Method method = testBeanClass.getDeclaredMethod("testMethod");
            Object object = testBeanClass.newInstance();
            //Call the method of the class
            method.invoke(object);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
   
}

  • Run the test class and the results are as follows:
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=63921:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\study\target\classes;D:\work\maven\mavenstore\org\openjdk\jol\jol-core\0.9\jol-core-0.9.jar ClassLoader.TestClassLoader
 The parent class loader of the custom class loader is: sun.misc.Launcher$AppClassLoader@18b4aac2
 Class loader is:ClassLoader.MyCloassLoader@1540e19d
ClassLoader.TestBean.testMethod()

Process finished with exit code 0

  • analysis:

1. The custom class loader needs to inherit Java Lang. classloader, override findClass method.
2. The content of the findClass method is to load the class file under the specified path, convert it into a byte array, and call the defineClass method of the parent class to convert the byte array into a class object.
3. It can be seen from the test class that the parent class loader of the custom class loader is sun misc. Launcher$AppClassLoader.
4. The test results show that the custom class loader successfully loads the class file under the specified path and the design is successful.

Reference blog
https://www.jianshu.com/p/1e4011617650
https://blog.csdn.net/huazai30000/article/details/85296671

Keywords: Java Back-end

Added by ben_m_gunn on Wed, 05 Jan 2022 18:29:20 +0200