Deep analysis of a kind of loading mechanism

The whole process of class I loading and running

Look at the program below

package com.maltose.jvm;

public class Math {
    public static final int initData = 666;
    public static User user = new User();

    //A method corresponds to a stack frame memory area
    public int compute() {  
        int a = 1;
        int b = 2;
        int c = (a + b) * 10;
        return c;
    }

    public static void main(String[] args) {
        Math math = new Math();
        math.compute();
    }
}

The process from running the main method in a class to the creation of the JVM, then loading the class to the bottom and finally running, and finally to the destruction of the JVM is as follows

Where java exe,jvm. DLLs are written in C/C + + (jvm.dll is a library function written in C/C + +, which is equivalent to the jar package in java);
In other words, the relevant programs started by the Java virtual machine (such as java.exe in the figure above) are implemented in C/C + +;

The more important part in the figure above is the red framed part (loadClass), that is, the process of loading the class into the JVM;

The class loading process of loadClass is as follows (finally, it needs to be loaded into the memory area of the jvm virtual machine):

Load > > verify > > prepare > > parse > > initialize > > use > > uninstall

  1. load
    The class file is initially on the hard disk, and then it is searched on the hard disk and read into the bytecode file through IO. In the loading phase, a Java. Java representing this class will be generated in memory Lang. class object is used as the access entry for various data of this class in the method area (it will be loaded only when the class is used, such as calling the class's main() method, new object, etc.)

  2. verification
    Verify the correctness of the bytecode file (. class) (as shown in the figure below, if you scribble in the bytecode file, it does not comply with the java virtual machine specification, and the verification will not pass)

  3. prepare
    Allocate memory to static variables of the class, The default value is specified by the JVM and has nothing to do with the value written in the program. For example, the default value of bollean is false, the object type is null by default, and the int type is 0 by default. Finally, the value written in the program is assigned after loading. If it is a constant modified by final, it is directly assigned to the value written in the program. There is no default value

  4. analysis
    Replace the symbolic reference with a direct reference (memory address reference). In this stage, some static methods (symbolic references, such as main method, return value, method modifier, method name, etc., are all called symbolic references) will be replaced with pointers or handles to the memory stored in the data (i.e. the location of the code in memory: direct reference). This is the static linking process (completed during class loading), The dynamic link is completed during the program running, replacing the symbolic reference with the direct reference;
    Explain static and dynamic links:
    For example, in the above static main method, the address in memory will not change after loading. For performance, the main method is changed into the address in memory during loading, which is a static link; But math The compute () method may change at run time, because it may be polymorphic or there may be different implementations of interfaces. Therefore, the specific implementation is not known at load time, and the specific implementation can only be known at run time. This situation that the location of the code in memory is determined at run time becomes a dynamic link;

  5. initialization
    Initialize the static variable of the class to the specified value (previously the default value, now it is initialized to the value specified in the code) and execute the static code block

Open math The class file is as follows:

javap instruction:


javap -v Math.class view the bytecode file (the assembly instructions of the JVM are listed below)

The above file is the same as the previous math Class files are all corresponding, but the above one is highly readable. Let's understand this file

There are many values in the constant pool:

The compute() method is also in the constant pool, and the corresponding constant pool location is as follows

math. The compute () method is not called when the class is loaded, that is, it will not be converted to a memory address during loading. Instead, when the code runs to this line, it goes to the memory to find the corresponding memory location. This process is called dynamic link

After the class is loaded into the method area, it mainly includes runtime constant pool, type information, field information, method information, reference of class loader, reference of corresponding class instance, etc.

Class loader reference: the reference from this class to the class loader instance
Reference of corresponding Class instance: after loading the Class information into the method area, the Class loader will create an object instance of corresponding Class type and put it into the heap as the entry and entry point for developers to access the Class definition in the method area.

Note: if the main class uses other classes during operation, these classes will be loaded step by step.
The classes in the jar package or war package are not loaded all at once. They are loaded only when they are used.

The code is as follows

public class TestDynamicLoad {
    static {
        System.out.println("*************load TestDynamicLoad************");
    }

    public static void main(String[] args) {
        new A();
        System.out.println("*************load test************");
        //B will not load unless new B() is executed here
        B b = null;  
    }
}

class A {
    static {
        System.out.println("*************load A************");
    }

    public A() {
        System.out.println("*************initial A************");
    }
}

class B {
    static {
        System.out.println("*************load B************");
    }

    public B() {
        System.out.println("*************initial B************");
    }
}

Operation results

The results show that:

  1. First execute the static code block of the main class, and then execute the main method in the main class;
  2. When new A(), first execute the static code block in class A (the static code block is executed when the class is loaded), and then execute the construction method;
  3. Since B is only defined, there is no new and B is not used, class B will not be loaded;

Class II loader

Class loader is actually a class. The above class loading process is mainly realized through class loader. There are the following kinds of loaders in Java

  • Boot class loader: it is implemented by C + + (we don't need to pay attention to it). It is responsible for loading the core class libraries under the lib directory of JRE that support the operation of the JVM, such as rt.jar and charsets Jar, etc
  • Extension class loader: it is responsible for loading the JAR class package in the extension directory under the ext folder under the lib directory of JRE that supports the operation of the JVM
  • Application class loader: it is responsible for loading the class package under the ClassPath path, mainly those classes written by yourself
  • Custom loader: it is responsible for loading the class package under the user-defined path

Firstly, the bootstrap class loader is implemented in C + +, which does not need to be considered; Through the Launcher class, C + + constructs the extension class loader and the application class loader in the process of initializing the Launcher class, and constructs the relationship between the extension class loader and the application class loader, that is, the parent class of the application class loader is the extension class loader

Take a look at an example of a class loader:

System.out.println(String.class.getClassLoader());
System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader());
System.out.println(TestJDKClassLoader.class.getClassLoader());

result

After C + + creates the boot class loader, C + + will call sun. Net in JAVA misc. Launcher (initializing the launcher class). This launcher is the initiator of the class loader in the JVM. After initializing this class, load other classes; In the process of initializing the launcher, all other class loaders will be generated;


Why string class. The output of getclassloader () is null?

Because it is not a java object, but an object generated by C + +, it cannot be obtained in java, so it is null;

All class loaders inherit from ClassLoader Java, each class loader has a parent attribute, which is a ClassLoader

Other class loaders:

package main.java.com.example.demoo.test;

import sun.misc.Launcher;
import java.net.URL;
public class TestJDKClassLoader {
    public static void main(String[] args) {
        System.out.println(String.class.getClassLoader());
        System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader());
        System.out.println(TestJDKClassLoader.class.getClassLoader());

        System.out.println("11111111111111111111111");
        ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
        ClassLoader extClassloader = appClassLoader.getParent();
        ClassLoader bootstrapLoader = extClassloader.getParent();
        System.out.println("the bootstrapLoader : " + bootstrapLoader);
        System.out.println("the extClassloader : " + extClassloader);
        System.out.println("the appClassLoader : " + appClassLoader);

        System.out.println("22222222222222222222222");
        System.out.println("bootstrapLoader Load the following files:");
        URL[] urls = Launcher.getBootstrapClassPath().getURLs();
        for (int i = 0; i < urls.length; i++) {
            System.out.println(urls[i]);
        }

        System.out.println("333333333333333333333333");
        System.out.println("extClassloader Load the following files:");
        System.out.println(System.getProperty("java.ext.dirs"));

        System.out.println("444444444444444444444444");
        System.out.println("appClassLoader Load the following files:");
        System.out.println(System.getProperty("java.class.path"));
    }
}

result

Class loader initialization process:

See the diagram of the whole process of class running and loading, which will create the JVM initiator instance sun misc. Launcher.
Inside the launcher constructor, it creates two class loaders, sun misc. Launcher. Extclassloader (extended class loader) and sun misc. Launcher. Appclassloader (application class loader).
By default, the JVM uses the instance of the class loader AppClassLoader returned by the Launcher's getClassLoader() method to load our application.

//Construction method of Launcher
public Launcher() {
    Launcher.ExtClassLoader var1;
    try {
        //Construct an extension class loader and set its parent loader to null during construction
        var1 = Launcher.ExtClassLoader.getExtClassLoader();
    } catch (IOException var10) {
        throw new InternalError("Could not create extension class loader", var10);
    }

    try {
        //Construct an application class loader, and set its parent loader to ExtClassLoader during construction,
        //The loader attribute value of the Launcher is AppClassLoader. We generally use this class loader to load applications written by ourselves
        this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
    } catch (IOException var9) {
        throw new InternalError("Could not create application class loader", var9);
    }

    Thread.currentThread().setContextClassLoader(this.loader);
    String var2 = System.getProperty("java.security.manager");
    . . .  . . .  //Omit some code that you don't need to pay attention to
}

Three parent delegation mechanism

The JVM class loader has a parent-child hierarchy, as shown in the following figure

In fact, there is a parent delegation mechanism for class loading. When loading a class, it will first entrust the parent loader to find the target class, and then entrust the upper parent loader to load if it cannot be found. If all parent loaders cannot find the target class under their own loading class path, they will find and load the target class in their own class loading path.

Note: the "parent loader" mentioned above is not a parent class;

For example, our Math class will first find the application class loader to load. The application class loader will first delegate the extension class loader to load, and then delegate the boot class loader. If the top-level boot class loader fails to find the Math class in its class loading path for a long time, it will return the request to load the Math class, After receiving the reply, the extended class loader loads itself. After looking for the Math class in its own class loading path for a long time, it fails to find the Math class, and then returns the Math class loading request to the application class loader. The application class loader then looks for the Math class in its own class loading path. As a result, it loads itself..

Question: why not start loading from the top-level boot class loader at the beginning?

For our web projects, 95% of the code is loaded in the underlying "application class loader". When the program is started for the first time, it really needs to go a long way to load, but after loading once, you only need to take it directly from the "application class loader"; If the boot class loader at the top level is used every time, after the first loading, you still need to go up from the bottom level to the top level every time;

The parent delegation mechanism is simpler, that is, find the father to load it first, and then the son to load it himself

Let's look at the source code of the parent delegation mechanism of the application class loader AppClassLoader loading class. The loadClass method of AppClassLoader will eventually call the loadClass method of its parent ClassLoader. The general logic of this method is as follows:

  1. First, check whether the class with the specified name has been loaded. If it has been loaded, it does not need to be loaded and returns directly.
  2. If this class has not been loaded, judge whether there is a parent loader; If there is a parent loader, it will be loaded by the parent loader (that is, call parent.loadClass(name, false);) Or call the bootstrap class loader to load.
  3. If neither the parent loader nor the bootstrap class loader can find the specified class, call the findClass method of the current class loader to complete the class loading.
//The loadClass method of ClassLoader implements the parental delegation mechanism
protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        // Check whether the current class loader has loaded the class
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                if (parent != null) {  //If the parent loader of the current loader is not empty, delegate the parent loader to load the class
                    c = parent.loadClass(name, false);
                } else {  //If the current loader parent loader is empty, delegate the boot class loader to load the class
                    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();
                //Will call the findClass method of URLClassLoader to find and load the class in the classpath of the loader
                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) {  //Will not execute
            resolveClass(c);
        }
        return c;
    }
}

Why design a parental delegation mechanism?

  • Sandbox security mechanism: write your own Java lang.String. Class class will not be loaded, which can prevent the core API library from being tampered with at will
  • Avoid repeated loading of classes: when the parent has loaded the class, it is not necessary to load the child ClassLoader again to ensure the uniqueness of the loaded class

Take a look at a class loading example (define a String class yourself):

//Note: the package name here is exactly the same as that of the String class of jdk
package java.lang;

public class String {
    public static void main(String[] args) {
        System.out.println("**************My String Class**************");
    }
}

Operation results:

error: In class java.lang.String Not found in main method, Please main Method is defined as:
   public static void main(String[] args)
otherwise JavaFX Application classes must be extended javafx.application.Application

When the loader loads Java lang.String. Class, the loaded loaders are application class loader - > extension class loader - > boot class loader. When the boot class loader arrives, the boot class loader finds Java under the lib package of jdk lang.String. Class (not the same as the string defined by ourselves), and the string class of jdk does not have a main method, so the error message is that the main method cannot be found;

Overall responsibility entrustment mechanism

"Overall responsibility" means that when a ClassLoder loads a class, unless another ClassLoder is displayed, the classes that the class depends on and references (other classes of new in the class) are also loaded by this ClassLoder.

Custom class loader example (write a class loader yourself):

The custom class loader only needs to inherit Java Lang. classloader class, which has two core methods, one is loadClass(String, boolean), which implements the two parent delegation mechanism, and the other is findClass, which is empty by default. Therefore, our custom class loader mainly rewrites the findClass method.

package main.java.com.example.demoo.test;

import java.io.FileInputStream;
import java.lang.reflect.Method;

public class MyClassLoaderTest {
    static class MyClassLoader extends ClassLoader {
        private String classPath;

        public MyClassLoader(String classPath) {
            this.classPath = classPath;
        }

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

        /**
         *
         * @param name Class name passed
         * @return
         * @throws ClassNotFoundException
         */
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            try {
                //Binary array of class files
                byte[] data = loadByte(name);
                //defineClass converts a byte array into a class object. This byte array is the final byte array after the class file is read.
                return defineClass(name, data, 0, data.length);
            } catch (Exception e) {
                e.printStackTrace();
                throw new ClassNotFoundException();
            }
        }

    }

    public static void main(String args[]) throws Exception {
        //When initializing the custom class loader, the parent class ClassLoader will be initialized first, and the parent loader of the custom class loader will be set as the application class loader AppClassLoader
        MyClassLoader classLoader = new MyClassLoader("D:/test");
        //Create test / COM / Turing / JVM directories on disk D, and copy the User class to User1 Class drop into the directory
        Class clazz = classLoader.loadClass("com.tuling.jvm.User1");
        Object obj = clazz.newInstance();
        Method method = clazz.getDeclaredMethod("sout", null);
        method.invoke(obj, null);
        //The class loader to print is
        System.out.println(clazz.getClassLoader().getClass().getName());
    }
}

result

=======Load the class and call the method with your own loader=======
com.tuling.jvm.MyClassLoaderTest$MyClassLoader

Break the parental delegation mechanism

For example, load a user class Class, if there is one in the user-defined loader, don't look in the loader above, just put the user in the user-defined loader Class is used, which breaks the parental delegation mechanism; (if it is a two parent delegation mechanism, it will find User.class from the parent loader)

The principle of breaking the parental delegation mechanism:
The loadClass method in the ClassLoader class has implemented the parent delegation mechanism. We only need to override this method;

After rewriting, delete the code that implements the parental delegation mechanism:

Another example of sandbox security mechanism is to try to break the parental delegation mechanism and load our own Java. Net with a custom class loader lang.String. class

import java.io.FileInputStream;
import java.lang.reflect.Method;

public class MyClassLoaderTest {
    static class MyClassLoader extends ClassLoader {
        private String classPath;

        public MyClassLoader(String classPath) {
            this.classPath = classPath;
        }

        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);
                return defineClass(name, data, 0, data.length);
            } catch (Exception e) {
                e.printStackTrace();
                throw new ClassNotFoundException();
            }
        }

        /**
         * Rewrite the class loading method to implement its own loading logic and do not delegate it to parents
         *
         * @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();
                    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;
            }
        }
    }

    public static void main(String args[]) throws Exception {
        MyClassLoader classLoader = new MyClassLoader("D:/test");
        //Try to use your own rewriting class loading mechanism to load your own Java lang.String. class
        Class clazz = classLoader.loadClass("java.lang.String");
        Object obj = clazz.newInstance();
        Method method = clazz.getDeclaredMethod("sout", null);
        method.invoke(obj, null);
        System.out.println(clazz.getClassLoader().getClass().getName());
    }
}

result

java.lang.SecurityException: Prohibited package name: java.lang
	at java.lang.ClassLoader.preDefineClass(ClassLoader.java:659)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:758)

Resolve error reporting

Tomcat breaks the parental delegation mechanism

Take Tomcat class loading as an example. Can Tomcat use the default parental delegation class loading mechanism?
Let's consider: Tomcat is a web container, so what problems does it solve:

  1. A web container may need to deploy two applications. Different applications may depend on different versions of the same third-party class library. It is not necessary to have only one copy of the same class library on the same server. Therefore, it is necessary to ensure that the class libraries of each application are independent and isolated from each other.
  2. Deployed in the same web container, the same class library and the same version can be shared. Otherwise, if the server has 10 applications, 10 copies of the same class library should be loaded into the virtual machine.
  3. The web container also has its own dependent class library, which can not be confused with the class library of the application. For security reasons, the class library of the container should be isolated from the class library of the program.
  4. The web container needs to support the modification of jsp. We know that the jsp file must be compiled into a class file to run in the virtual machine, but it is common to modify jsp after the program runs. The web container needs to support the modification of jsp without restarting.

Let's take another look at our question: can Tomcat use the default parental delegation class loading mechanism?
The answer is No. Why?
First, if you use the default class loader mechanism, you cannot load different versions of the same class library. No matter what version you are, the default class loader only cares about your fully qualified class name, and there is only one copy.
The second problem is that the default class loader can be implemented because its responsibility is to ensure uniqueness.
The third question is the same as the first.
Let's look at the fourth question. We think how to realize the hot loading of jsp files. jsp files are actually class files. If they are modified, but the class name is still the same, the class loader will directly take the existing ones in the method area, and the modified jsp will not be reloaded. So what? We can directly uninstall the class loader of the jsp file, so you should think that each jsp file corresponds to a unique class loader. When a jsp file is modified, we can directly uninstall the jsp class loader. Recreate the class loader and reload the jsp file.

Tomcat custom loader details

Several main class loaders of tomcat:

  • commonLoader: Tomcat's most basic class loader. The classes in the loading path can be accessed by the Tomcat container itself and various webapps;
  • catalinaLoader: the private class loader of Tomcat container. The classes in the loading path are not visible to Webapp;
  • sharedLoader: the class loader shared by each Webapp. The classes in the loading path are visible to all webapps, but not to the Tomcat container;
  • WebappClassLoader: the private class loader of each Webapp. The classes in the loading path are only visible to the current Webapp. For example, load the relevant classes in the war package. Each war package application has its own WebappClassLoader to realize mutual isolation. For example, different war package applications have introduced different spring versions, so that the implementation can load their own spring versions;

As can be seen from the delegation relationship in the figure:
All classes that can be loaded by CommonClassLoader can be used by CatalinaClassLoader and SharedClassLoader, so as to realize the sharing of public class libraries, while the classes that CatalinaClassLoader and SharedClassLoader can load are isolated from each other.
WebAppClassLoader can use the classes loaded by SharedClassLoader, but each WebAppClassLoader instance is isolated from each other.
The loading range of Jasper loader is only the one compiled by the JSP file Class file, which appears to be discarded: when the Web container detects that the JSP file has been modified, it will replace the current JasperLoader instance, and realize the hot loading function of JSP file by establishing a new JSP class loader.

Does the tomcat loading mechanism violate the parental delegation model recommended by java? The answer is: Yes.
Obviously, tomcat is not implemented in this way. In order to achieve isolation, tomcat does not abide by this Convention. Each webappClassLoader loads the class files in its own directory and will not pass them to the parent class loader, breaking the parent delegation mechanism.

Simulate the webappClassLoader of Tomcat to load its own war package. Different versions of classes in the application can coexist and isolate each other

public class MyClassLoaderTest {
    static class MyClassLoader extends ClassLoader {
        private String classPath;

        public MyClassLoader(String classPath) {
            this.classPath = classPath;
        }

        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);
                return defineClass(name, data, 0, data.length);
            } catch (Exception e) {
                e.printStackTrace();
                throw new ClassNotFoundException();
            }
        }

        /**
         * Rewrite the class loading method to implement its own loading logic and do not delegate it to parents
         * @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();

                    //Non custom classes are loaded by parental delegation
                    if (!name.startsWith("com.tuling.jvm")){
                        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;
            }
        }
    }

    public static void main(String args[]) throws Exception {
        MyClassLoader classLoader = new MyClassLoader("D:/test");
        Class clazz = classLoader.loadClass("com.tuling.jvm.User1");
        Object obj = clazz.newInstance();
        Method method= clazz.getDeclaredMethod("sout", null);
        method.invoke(obj, null);
        System.out.println(clazz.getClassLoader());
        
        System.out.println();
        MyClassLoader classLoader1 = new MyClassLoader("D:/test1");
        Class clazz1 = classLoader1.loadClass("com.tuling.jvm.User1");
        Object obj1 = clazz1.newInstance();
        Method method1= clazz1.getDeclaredMethod("sout", null);
        method1.invoke(obj1, null);
        System.out.println(clazz1.getClassLoader());
    }
}

Operation results:

=======Load the class and call the method with your own loader=======
com.tuling.jvm.MyClassLoaderTest$MyClassLoader@266474c2

=======Another one User1 Version: calling methods by loading classes with your own loader=======
com.tuling.jvm.MyClassLoaderTest$MyClassLoader@66d3c617

Note: in the same JVM, two class objects with the same package name and class name can coexist. Because their class loaders can be different, it depends on whether the two class objects are the same. In addition to whether the package name and class name of the class are the same, they also need the same class loader to think they are the same.

Simulate the hot loading of JasperLoader of Tomcat
Principle: the background startup thread listens for jsp file changes. If changes occur, find the loader reference (gcroot) of the servlet class corresponding to the jsp, regenerate a new JasperLoader loader, assign a value to the reference, and then load the servlet class corresponding to the new jsp. The previous loader will be destroyed at the next gc because there is no gcroot reference.

The Hotspot source JVM starts the process of executing the main method

Keywords: Java jvm

Added by Mr_jmm on Mon, 03 Jan 2022 00:26:39 +0200