Mind mapping


The paper has collected to making choice, welcome Star:https://github.com/yehongzhi/learningSummary

Introduction to JVM

Before we get into the JVM, let’s take a look at the.java file from coding to execution:


The entire process is that x. Java files need to be compiled into X. lass files, which are loaded into memory through the class loader, interpreted and compiled by the interpreter or just-in-time compiler, and finally delivered to the execution engine, which operates the OS hardware.

From the classloader to the execution engine is the JVM.

The JVM is a cross-language platform. As you can see from the figure above, instead of a.java file, you actually run a.class file on the JVM. This leads to the idea that the JVM is a cross-language platform that can run not just Java programs, but any programming language that can be compiled into a.class file that the JVM recognizes.

So in addition to Java, there are many other languages that can run on the JVM, such as JRuby, Groovy, Scala, Kotlin, and so on.

The JVM is essentially a computer virtualized by software, with its own set of instructions, and its own operating system.

So Oracle created a JVM specification for the JVM, and Oracle provided its implementation. Basically the most widely used Java virtual machine implementation today, called Hotspot. Use Java -version to view:


Some large companies with a certain scale will also develop their own JVM virtual machines, such as TaobaoVM of taobao, j9-ibm of IBM, MicrosoftVM and so on.

JDK, JRE, JVM


The JVM should know that it is a virtual machine running. Class files. The JRE is the runtime environment, including the JVM and the Java core library, which cannot run without the core.


The JDK includes the JRE and several development toolsets.

So the overall relationship is JDK > JRE > JVM.

Class loading process

Class loading is an important part of how the JVM works, and we know that a class is a file that exists on hard disk. So you need to differentiate yourself from other programmers, and you need to understand that.

The class Loading process is actually divided into three steps: Loading, Linking, and Initlalizing.

The second Linking step is divided into three steps: Verification, Preparation, and Resolution.


3.1 Loading

Loading loads.Class bytecode files into memory, converts this data into runtime data in the method area, and generates a java.lang. class object in the heap to represent this class as an access point to these types of data in the method area.

3.2 Linking

Linking simply means combining the information from the original class definition into the JVM health state. It is divided into three small steps.

3.2.1 Verification

Verify that the loaded class information complies with class file standards and prevent malicious messages or byte messages that do not conform to the specification. It is an important guarantee for the safe operation of THE JVM VIRTUAL machine.

3.2.2 Preparation

Create a static variable in a class or interface and initialize the static variable to a default value. Static int I = 5; static int I = 5; static int I = 5; The assignment to 5 is a later step.

3.2.3 Resolution

Convert symbolic references used in the class file constant pool into direct memory addresses, which are directly accessible.

3.3 Initlalizing

This step actually performs the code logic of the class initializing Clinit ()(class constructor), including the action of static field assignment and the logic of executing the static code block (static{}) in the class definition. When initializing a class, the parent class is initialized first. The virtual machine ensures that a class’s Clinit () methods are locked and synchronized correctly in a multithreaded environment.

Class loaders

This is the whole process of class loading. The last step, Initlalizing, loads the class through the class loader. Class loaders, I’m going to talk about them separately, because that’s an important point.

Classloaders in Java are classified from top to bottom:

  • Bootstrap ClassLoader
  • ExtClassLoader (Extended class loader)
  • AppClassLoader (Application class loader)

From the class diagram, you can see that ExtClassLoader and AppClassLoader are both subclasses of ClassLoader.


So if you want to customize a ClassLoader, you can inherit the ClassLoader abstract class and override the methods in it. We’ll talk about what method to override later.

5. Parent delegation mechanism

So class loaders, how these class loaders work. You’ve probably heard of the parent delegate mechanism, but it doesn’t matter if you haven’t. I’m going to talk about it.

There are Bootstrap, ExtClassLoader, and AppClassLoader class loaders. The working mechanism is as follows:


The core code for loading classes is found in the JDK source code, in the abstract ClassLoader class loadClass(), interested in the source code to see:

protectedClass<? > 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) {

            long t0 = System.nanoTime();

            try {

                if(parent ! =null) {

                    // If there is a class loader on top, recurse up and look for the class loader on top

                    c = parent.loadClass(name, false);

                } else {

                    c = findBootstrapClassOrNull(name);

                }

            } catch (ClassNotFoundException e) {

                // ClassNotFoundException thrown if class not found

                // from the non-null parent class loader

            }

   // If none of the upper classes can find the corresponding class

            if (c == null) {

                // If still not found, then invoke findClass in order

                // to find the class.

                long t1 = System.nanoTime();

                // Load it yourself

                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) {

            resolveClass(c);

        }

        return c;

    }

}

Copy the code

In fact, the whole logic is pretty clear, and to make it easier to understand, let me draw a picture for you, to make it easier to understand:


At this point, the flow of the parent delegate mechanism should be clear. The point is, why use parental delegation?

If the interviewer asks this question, be sure to answer with the key word: security.

Dialectic by contradiction. If I don’t use parental delegation, I can create a custom class loader, and then I write a java.lang.String class and load it into the custom class loader. Don’t bring hidden trouble to the safety of virtual machine. Therefore, it is necessary to ensure that a class can only be loaded by the same class loader to ensure the security of the system class.

Custom class loaders

Custom class loaders, as described above, can be used to create a custom class that inherits the ClassLoader abstract class. Which method do I override? The loadClass() method is used to load classes.

Overwriting loadClass() would prove thoughtful, but not quite right, because overwriting loadClass() would break the logic of the parent delegate mechanism. The findClass() method in loadClass() should be overridden.

The findClass() method is how a custom classloader loads a class.


What’s the source code for the findClass() method?


This method is obviously intended for subclass overrides, and the permission modifier is protected. Otherwise, an exception will be thrown that the class cannot be found. Those of you who have studied design patterns will recognize that this is the design pattern of the template pattern. So we can rewrite this method with our own class loader. Get started!

Create a CustomerClassLoader class that inherits the findClass() method of the ClassLoader abstract class.

public class CustomerClassLoader extends ClassLoader {

 // The path of the class file on disk

    private String path;

 // Initializes the path to the class file through the constructor

    public CustomerClassLoader(String path) {

        this.path = path;

    }



    / * *

* class is loaded

     *

     * @paramFull path of the name class

     * @returnClass<? >

     * @author Ye hongzhi

* /


    @Override

    protectedClass<? > findClass(String name)throws ClassNotFoundException {

        Class clazz = null;

        // Get the class file and convert it to a bytecode array

        byte[] data = getData();

        if(data ! =null) {

            // Convert the bytecode array of class to an instance of class

            clazz = defineClass(name, data, 0, data.length);

        }

        // Return the Class object

        return clazz;

    }



    private byte[] getData() {

        File file = new File(path);

        if (file.exists()) {

            try (FileInputStream in = new FileInputStream(file);

                 ByteArrayOutputStream out = new ByteArrayOutputStream();) {

                byte[] buffer = new byte[1024];

                int size;

                while((size = in.read(buffer)) ! = -1) {

                    out.write(buffer, 0, size);

                }

                return out.toByteArray();

            } catch (IOException e) {

                e.printStackTrace();

                return null;

            }

        } else {

            return null;

        }

    }

}

Copy the code

Now that we’re done, let’s test by defining a Hello class.

public class Hello {

    public void say(a) {

        System.out.println("hello....... java");

    }

}

Copy the code

Compile to a class file using the javac command as shown below:


Finally, write a main method to run the test:

public class Main {

    public static void main(String[] args) throws Exception {

        String path = "D:\\mall\\core\\src\\main\\java\\io\\github\\yehongzhi\\classloader\\Hello.class";

        CustomerClassLoader classLoader = new CustomerClassLoader(path);

Class<? > clazz = classLoader.findClass("io.github.yehongzhi.classloader.Hello");

        System.out.println("Using the class loader:" + clazz.getClassLoader());

        Method method = clazz.getDeclaredMethod("say");

        Object obj = clazz.newInstance();

        method.invoke(obj);

    }

}

Copy the code

Running results:


Break the parental delegation mechanism

This is gonna make you wonder. Why break the parent delegate mechanism in order to keep the system safe?

If you go back to the parent delegate mechanism, remember that the bottom class loader always delegates to the top class loader, and if the top class loader is already loaded, it doesn’t need to be loaded, and the top class loader doesn’t load itself. This highlights a flaw in the parent delegate mechanism, which is that only the child class loader can delegate to the parent class loader, and not the parent class loader to delegate to the child class loader.

So you ask, when does a parent class loader delegate to a child class loader?

There is a scenario where the database driver loads JDBC. There is an interface in the JDK that all JDBC drivers need to implement, java.sql.driver. The implementation classes of the Driver interface are provided by the major database vendors. The problem is that DriverManager(JDK rt.jar) loads the implementation classes that implement the Driver interface and manages them all, but DriverManager is loaded by the Bootstrap class loader. Only files in the JAVA_HOME lib directory can be loaded (see the first diagram of the parent delegate mechanism above), but the implementation classes are provided by the service provider and loaded by the AppClassLoader, which requires Bootstrap to delegate to the AppClassLoader. You break the parent delegate mechanism. This is just one scenario, but there are many more examples of breaking parental delegation.

So how do you break the parent delegate mechanism?

  • The easiest way to do this is to create a custom class loader that overwrites the findClass() method without breaking the parent delegate mechanism, so if I want to break the parent delegate mechanism, I override the loadClass() method and change the logic of the parent delegate mechanism directly. Rewriting this method is not recommended after JDK1.2. So provide the following approach.
  • Use Thread Context classloaders. This classloader can be set through the setContextClassLoader() method of the java.lang.Thread class. If it has not been set when the Thread is created, it will inherit one from the parent Thread; This class loader is the AppClassLoader class loader by default if it is not set at the global scope of the application.

So in what way does JDBC break the parent delegation mechanism?

Using the context file class loader, of course, and the SPI mechanism, which is broken down step by step.

In the first step, Bootstrap loads the DriverManager class and calls the initialization method in a static code block of the DriverManager class.

public class DriverManager {

    static {

        loadInitialDrivers();

        println("JDBC DriverManager initialized");

    }

}

Copy the code

The second step is to load all the implementation classes of the Driver interface, get the set of Driver implementation classes, and get an iterator.


Step 3, look at the serviceloader.load () method.




Step 4, look at driversIterator.


And then you keep looking, and you come to an amazing place.


The constant PREFIX value is:

private static final String PREFIX = "META-INF/services/";

Copy the code

So we can find this file in the mysql driver package:


Find the implementation class of the interface by filename, which is Java’s SPI mechanism. That’s it, my Lord!

As a warm guy, let me draw a picture to summarize the process:


conclusion

This article focuses on the JVM, then covers the three steps of the JVM’s classloading mechanism, followed by a custom classloader and the parent delegate mechanism. Finally, we delve into why we should use and break the parent delegation mechanism. It may be a little long, but I believe I understand everything, because I’m speaking in a colloquial way, and it’s well illustrated.

The code for all of the above examples is uploaded to Github:

https://github.com/yehongzhi/mall

Please give me a thumbs-up if you think it is useful. Your thumbs-up is the biggest motivation for my creation

Refusing to be a salt fish, I’m a programmer trying to be remembered. See you next time!!

Ability is limited, if there is any mistake or improper place, please criticize and correct, study together!