Class loader subsystem

Keywords: Java intellij-idea

Parsing the. Class file javap -v xxxxx.class

Or IDEA to install the jclasslib plug-in

Class loader subsystem

Class loader and loading process

  1. The class loader subsystem is responsible for loading class files from the file system or network. Class files have a specific file ID at the beginning of the file
  2. ClassLoader is only responsible for loading class files. Whether it can run or not is determined by the execution engine
  3. The loaded class information is stored in a memory space called the method area. In addition to the class information, the method area also stores runtime constant pool information, which may also include string literal and numeric constants

Loading

  1. Get the binary byte stream defining this class through the fully qualified class name of a class
    • Class file
    • Classic scenario of network acquisition: Web Applet
    • zip package to obtain jar ear war format
    • Classic scenario of generating other files: JSP Application
    • Dynamic agent technology is the most used in runtime computing generation
    • Reading from the database is rare
    • Anti decompilation of encrypted file reading
    • ...
  2. The static storage structure represented by this byte stream is transformed into the runtime data structure of the method area
  3. Generate a java.lang.Class object (reflection) representing this class in memory as an access point for various data of this class in the method area

The loading phase can be completed either by the built-in startup class loader of the Java virtual machine or by the user-defined class loader

Verify

  1. The purpose is to ensure that the information contained in the byte stream of the class file meets the requirements of the current virtual machine and that the correctness of the loaded class will not endanger the security of the virtual machine

  2. It mainly includes four kinds of verification: file format verification, metadata verification, bytecode verification, symbol reference verification

    • The specific identification verification at the beginning of the class file is performed at this stage

    • Illegal. VerifyError exception or subclass exception will be thrown

Prepare

  1. Allocate memory for the class variable (static variable) and set the default initial value of the variable, that is, zero

    private static int a = 1;// prepare: a = 0; ----> init: a = 1;
    
  2. static modified with final is not included here, because final will be allocated during compilation and will be explicitly initialized in the preparation stage

    public static final int a = 5; // prepare: a = 5;
    
  3. Initialization class variables will not be allocated for instance variables here. Variables will be allocated in the method area, and instance traversal will be allocated to the Java heap along with the object

    public int = 3; // It will not be initialized in the prepare phase
    

Resolve resolve

  1. The process of converting a symbolic reference in a constant pool to a direct reference

  2. In fact, the parsing operation is often followed by the JVM after initialization

  3. A symbolic reference is a set of matches that describe the referenced target. The literal form of symbol reference is clearly defined in the Class file format of java virtual machine specification. A direct reference is a pointer directly to the target, a relative offset, or a handle indirectly located to the target

  4. Parsing actions are mainly for classes or interfaces, fields, class methods, interface methods, method types, etc. Corresponding to constant in constant pool_ Class_ info,CONSTANT_Fieldref_info,CONSTANT_Methodref_info, etc

  5. Access to methods or fields will also check their accessibility (public protected private < package >) in the parsing phase

initialization

  1. The initialization phase is the process of executing the class constructor method < clinit > ()

  2. This method does not need to be defined. It is the combination of the assignment action of all class variables in the class automatically collected by the javac compiler and the statements in the static code block (if not, this method will not be generated)

  3. The instructions in the constructor method are executed in the order in which the statements appear in the source file

    private static int num = 1;
    static {
        num = 2;
        number = 20;
        System.out.println(num);
        System.out.println(number); //Error reporting: illegal forward reference
    }
    private static int number = 10; // prepare: number = 0; --> initialization: number = 20; --> number = 10;
    

  4. < client > () is different from the class constructor (Association: the constructor is < init > () from the perspective of virtual machine)

    //After any class declaration, there is at least one class constructor inside
    private int a = 1;
    public static void main(String[] args){
        int b = 2;
    }
    public ClientTest() {
        a = 10;
        int d = 20;
    }
    

  5. If the class has a parent class, the JVM will ensure that the < clinit > () of the parent class has been executed before the < clinit > () of the child class is executed

    static class Father {
        public static int A = 1;
        static{
            A = 2;
        }
    }
    static class Son extends Father() {
        public static int B = A;
    }
    
    psvm() {
        //Load the Father class first, and then the Son class
        System.out.println(Son.B); // 2
    }
    

  6. The virtual machine must ensure that the < client > () method of a class is locked synchronously under multiple threads, that is, if multiple threads initialize a class at the same time, only one thread will execute the < client > () method of this class, and other threads need to wait. If there are long-time operations in < client > (), thread blocking will be caused

    class DeadThread{
        static {
            if(true) {
                sout(Thread.currentThread().getName() + "Initialize this class");
                while(true) {
                    
                }
            }
        }
    }
    
    Thread t1 = ....;
    Thread t2 = ....;
    t1.start();
    t2.start();
    
    // final result
    // Thread 2 initializes the class
    // Because static internal while(true) is an endless loop, if this class will be loaded twice, the South statement will be executed twice
    // The result shows that thread 1 cannot load the class when thread 2 loads the class. Thread 2 will lock the class and the class will be loaded only once
    

Classification of class loaders

BootStrap ClassLoader and User Defined ClassLoader

Custom class loader generally refers to a class loader customized by developers in the program, but it is not defined in the Java virtual machine specification. Instead, all class loaders derived from the abstract class ClassLoader are divided into custom class loaders

public class ClassLoaderTest {
    public static void main(String[] args) {
        //Get system class loader
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2

        //Get its upper layer: extension class loader
        ClassLoader extClsLoader = systemClassLoader.getParent(); //The upper class is not a parent class
        System.out.println(extClsLoader);//sun.misc.Launcher$ExtClassLoader@1b6d3586

        //Get its upper bootstrap clsloader, unable to get the boot class loader
        ClassLoader bootstrapClsLoader = extClsLoader.getParent();
        System.out.println(bootstrapClsLoader); //null

        //For user-defined classes: load using the system class loader
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2

        //The String class uses the boot class loader, and the Java core class libraries are loaded with the boot class loader
        ClassLoader stringLoader = String.class.getClassLoader();
        System.out.println(stringLoader); //null
    }
}

Start the class loader (BootStrap ClassLoader)

  1. Nested inside the JVM using C/C + + language

  2. The core library used to load Java (JAVA_HOME/jre/lib/rt.jar, resources.jar or the contents in sun.boot.class.path path) is used to provide classes required by the JVM itself

  3. Does not inherit from java.lang.ClassLoader. There is no parent loader

  4. Load extension classes and application class loaders and specify them as their parent class loaders

  5. For security reasons, the BootStrap startup class loader only loads classes with package names beginning with java, javax and sun

  6. It cannot be directly referenced by Java programs. When writing a custom class loader, if you need to delegate the request to the startup class loader, you can use null instead

    //Start class loader
    //Get the api path that bootstrap classloader can load
    URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
    for (URL urL : urLs) {
        System.out.println(urL.toExternalForm());
    }
    //Select a class from the above path and look at its classloader: boot classloader
    ClassLoader classLoader = Provider.class.getClassLoader();
    System.out.println(classLoader);
    

Extension ClassLoader

  1. Written in Java language and implemented by sun.misc.Launcher$ExtClassLoader (internal class of Launcher class)

  2. Derived from the CLassLoader class

  3. The parent class loader is the boot class loader

  4. Load the class library from the directory specified by the java.ext.dirs system attribute or 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 extension class loader

    //extensions class loader 
    String extDirs = System.getProperty("java.ext.dirs");
    for (String path : extDirs.split(";")) {
        System.out.println(path);
    }
    //Select a class from the above path and see its classloader: extended classloader
    ClassLoader classLoader = CurveDB.class.getClassLoader();
    System.out.println(classLoader);
    

Application class loader (system class loader AppClassLoader)

  1. java programming is implemented by sun.misc.Launcher$AppClassLoader (internal class of Launcher class)
  2. Derived from ClassLoader class
  3. The parent class loader is an extended class loader
  4. It is responsible for loading the class library under the path specified by the environment variable classpath or the system attribute java.class.path
  5. This class loader is the default class loader in the program. Generally speaking, it is used to load the classes of Java applications
  6. This class loader can be obtained through the ClassLoader#getSystemClassLoader() method

User defined class loader

Custom class loaders are used only when necessary. Generally, the above three kinds of loaders are used

Why use a custom class loader?

  1. Isolated class loader
  2. Modify how classes are loaded
  3. Extended load source
  4. Prevent source code leakage

Implementation steps:

  1. Implement your own class loader by inheriting the abstract class java.lang.ClassLoader
  2. Before JDK1.2, you need to inherit ClassLoader and override the loadClass() method. After 1.2, write the custom class loading logic in the findClass() method
  3. When writing a custom class loader, you can directly inherit the URLClassLoader class if you don't have too complex requirements. In this way, you can avoid writing the findClass() method and its way to obtain the byte code stream, making the writing of the custom class loader more concise
public class CustomClassLoader extends ClassLoader {
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {

        try {
            byte[] result = getClassFromCustomPath(name);
            if(result == null){
                throw new FileNotFoundException();
            }else{
                return defineClass(name,result,0,result.length);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        throw new ClassNotFoundException(name);
    }

    private byte[] getClassFromCustomPath(String name){
        //Load specified class from custom path: Details
        //If the bytecode file of the specified path is encrypted, decryption is required in this method.
        return null;
    }

    public static void main(String[] args) {
        CustomClassLoader customClassLoader = new CustomClassLoader();
        try {
            Class<?> clazz = Class.forName("One",true,customClassLoader);
            Object obj = clazz.newInstance();
            System.out.println(obj.getClass().getClassLoader());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

ClassLoader

Is an abstract class, and all subsequent class loaders inherit from ClassLoader (excluding startup class loader)

Ways to get ClassLoader:

  1. Gets the ClassLoader of the current class

    cls.getClassLoader();
    
  2. Gets the ClassLoader of the current thread context

    Thread.currentThread().getContextClassLoader();
    
  3. Gets the ClassLoader of the system

    ClassLoader.getSystemClassLoader();
    
  4. Gets the ClassLoader of the caller

    DriverManager.getCallerClassLoader();
    
            //1. null boot class loader
            ClassLoader classLoader = Class.forName("java.lang.String").getClassLoader();
            System.out.println(classLoader);
            //2. sun.misc.Launcher$AppClassLoader@18b4aac2
            ClassLoader classLoader1 = Thread.currentThread().getContextClassLoader();
            System.out.println(classLoader1);

            //3.sun.misc.Launcher$ExtClassLoader@28a418fc System class loader. Getparent() - > extended class loader
            ClassLoader classLoader2 = ClassLoader.getSystemClassLoader().getParent();
            System.out.println(classLoader2);

Parental delegation mechanism

The Java virtual machine uses the on-demand loading method for class files. When the class needs to be used, its class files will be loaded into memory to generate class objects, and when the class files of a class are loaded, the Java virtual machine adopts the parental delegation mode, that is, the request is handled by the parent class. It is a task delegation mode

Working process:

  1. If a class loader receives a class loading request, it will not try to load the class itself, but delegate the request to the parent class loader to complete it
  2. If the parent class loader still has its parent class loader, it further delegates up and recursively requests to reach the top-level startup class loader
  3. If the parent class loader can complete the class loading task, it will return successfully. If the parent class loader cannot complete the loading task, the child loader will try to load it by itself. This is the two parent delegation mechanism

If a user customizes a java.lang package and creates a String class under the package, what happens when the user calls java.lang.String()?

  1. First, the class loader of the user-defined String class will not load itself, but pass it to the upper layer
  2. When passed to the boot class loader, the boot class loader finds that java.lang.String is within its loading range, so it loads java.lang.String
  3. At this time, the child loader will not execute, so when calling java.lang.String(), it returns String in the Java core library

What happens if the user defines the main method in the custom String class?

  1. As can be seen from above, the bootstrap class loader is used when the custom String class is loaded

  2. The String class in the core library does not have a main method, so an error will be reported

Advantages:

  1. Avoid repeated loading of classes
  2. Protect program security and prevent core API s from being tampered with * * (sandbox security mechanism)**

What happens if a class is created and loaded under the user-defined package java.lang?

Throw security exceptions to fully protect the security of the core API

other

Two necessary conditions for identifying whether two class objects exist for the same class in the JVM:

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

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

Reference to class loader:

The JVM must know whether a type is loaded by the boot loader or the user class loader. If a type is loaded by the user class loader, the JVM will save a reference of the 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 class loaders of the two types are the same

Active and passive use of classes:

Active use:

  1. Create an instance of a class
  2. Access or assign a value to a static variable of a class or interface
  3. Calling a static method of a class
  4. reflex
  5. Initializes a subclass of a class
  6. A class marked as a startup class when the Java virtual machine starts
  7. JDK7 starts to provide dynamic language support: the parsing result of java.lang.invoke.MethodHandle instance is REF_getStatic,REF_putStatic,REF_ If the class corresponding to the invokestatic handle is not initialized, it will be initialized

In addition to the above seven cases, the passive use of classes will not lead to class initialization (the initialization phase may not be executed)

Loaded by the user class loader. If a type is loaded by the user class loader, the JVM will save a reference of the 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 class loaders of the two types are the same

Active and passive use of classes:

Active use:

  1. Create an instance of a class
  2. Access or assign a value to a static variable of a class or interface
  3. Calling a static method of a class
  4. reflex
  5. Initializes a subclass of a class
  6. A class marked as a startup class when the Java virtual machine starts
  7. JDK7 starts to provide dynamic language support: the parsing result of java.lang.invoke.MethodHandle instance is REF_getStatic,REF_putStatic,REF_ If the class corresponding to the invokestatic handle is not initialized, it will be initialized

In addition to the above seven cases, the passive use of classes will not lead to class initialization (the initialization phase may not be executed)

Posted by HK2ALL on Wed, 10 Nov 2021 21:10:04 -0800