Introduction to the

This introduction to class loaders, including parent delegation and code analysis, SPI, etc., hope you have fun learning, enjoy learning

Supporting the video tutorial: www.bilibili.com/video/BV173… (Updates may be late but not absent)

A preliminary understanding

Class loader action

We know that Java code is compiled into class bytecode and loaded into the JVM. What is that loaded by? That “thing” is the classloader

Class loader classification

The JDK provides class loaders

  • Bootstrap ClassLoader
  • Extension ClassLoader
  • Application ClassLoader

Class loader division of labor

Division of labor: Essentially, each class loader only loads the content under a certain path

Application class loader: Loads all the class files under the classpath. See the following figure for details

Extension class loader: jre/lib/ext/ is loaded

Start the class loader and load /jre/lib/rt.jar

Parents delegate

When it comes to class loaders, we can’t help but mention the term “parent delegate.” Parent delegate sounds obscure, but it’s actually quite simple. This can be interpreted as a collaboration between class loaders, combined with diagrams to understand the text below.

If you need to load a class now (such as new Test() in your code, load the Test class)

  1. The application looks for it in its cache, returns if it finds it, and lets the extension classloader look for it if it doesn’t

(Assuming that the application class loader is not found, so it goes to the extension class loader)

  1. The extension class loader also looks in its cache and returns if it can find it. If it can’t find it, the launcher class loader looks for it

(Assuming that the extension class loader is not found, so we go to the start class loader)

  1. Jar: /jre/li/rt.jar: /jre/li/rt.jar: /jre/li/rt.jar

4. The extension class loader will also search its own path (jre/lib/ext/), and if it fails to find it, it will continue to throw the pan back to the application class loader

  1. The application class loader looks for it in the classpath and throws a ClassNotFound exception if it doesn’t find it

Tip: Parent-child relationships in classloaders are logical parent-child relationships, not extend in code

Why parent delegate

Safe, safe, safe.

Tens of thousands of lines of code, security first.

If you define a java.lang.String class and put it in your classpath, it would be dangerous to load it directly into memory by the application class loader, because that means you could replace the JDK’s original String class that way. And then do something about it like, (transfer money to your bank card)

Look at the source code

Let’s take it a step further by peeking through the source code to take a closer look at the parent delegate mechanism. Next, I’ll cut out the key location code to explain. Please combine the theoretical content of the first half of the understanding

C + + code

Since Java runs on the JVM, take a look at the c++ section of the code to get to the source of the problem

LoandMainCLass: The class that loads the main method in our Java code (java.c file)

After entering loandMainCLass, you can see that the GetStaticMethodID method is called and the checkAndLoadMain parameter is passed, which is the watershed point from which it enters the Java code

GetStaticMethodID gets the ID of the static function main

The Java part

The type of scloader is AppClassLoader

Let’s take a look at AppClassLoader

It inherits UrlClassLoader

UrlClassLoader inherits SecureClassLoader

SecureClassLoader inherits ClassLoader

comb

LoadClass (AppClassLoader, URLClassLoader, SecureClassLoader) is not overwritten to loadClass

Let’s take a look at loadClass

LoadClass(name,false) is called. This method is overridden by the AppClassLoader, so the AppClassLoader focuses on LoadClass

This method eventually calls the LoadClass of the parent class, also known as ClassLoader.

Here is the LoadClass method in ClassLoader. I personally think the following code is particularly concise. Let’s worship the mind of the great God

protectedClass<? > loadClass(String name,boolean resolve)
    throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        // First, check if the class has already been loadedClass<? > c = findLoadedClass(name);if (c == null) {
            long t0 = System.nanoTime();
            try {
                if(parent ! =null) {
                    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 (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 statssun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); }}if (resolve) {
            resolveClass(c);
        }
        returnc; }}Copy the code

FindLoadedClass: Find the loaded class, because it is not currently loaded, so this must be null

Let the “parent” loader load, you can see that the parent loader is of type ExtClassLoader.

Let’s take a look at the ExtClassLoader code

Its inheritance is similar to that of AppClassLoader

Back to parent. LoadClass, ExtClassLoader also inherits ClassLoader, so it ends up there again, but notice that this is ExtClassLoader

Obviously, the ExtClassLoader’s findLoadedClass is also null, so it’s going to go to findBootstrapClassOrNull

Tip: the parent loader for ExtClassLoader is BootStrap written in c++. As you can see in the figure below, findBootstrapClassOrNull ends up calling the native method

FindBootstrapClassOrNull throws a ClassNotFoundException while the class to be loaded is our own and should be loaded by the application classloader

After the exception is caught, the ExtClassloader tries to load the class in its own directory, which of course fails to load and eventually throws an exception

Once the application class loader catches the exception, it will also try to load the class itself (from the classpath), because our class exists in the classpath and can be loaded, otherwise it will throw a ClassNotFoundException

At this point, the parent delegate code is pretty much done. Let’s take a look at how parent is assigned

Go back to where you started

Take a look at the scloader definition,

Then look at getSystemClassLoader

There is a line of sun. Misc. The Launcher. GetLauncher ();

Look at constructors

This is where ExtClassLoader and AppClassLoader are created

The parent of ExtClassLoader is null

The parent of AppClassLoader is ExtClassLoader

That’s it for the important part of the code

spi

Bypass parental delegation

Before we talked about SPI, we learned that when our class A uses another class B, assuming that class B has not been loaded before, then we have to load class B. To load class B, we need to use the class loader. So which loader do we use? It’s A class A loader.

This creates a problem (for EXAMPLE, JDBC)

The driver is loaded by the launcher class in rt.jar, but the database driver implementation provided by various vendors is not loaded by the launcher class loader in classpath

The solution to this problem is to use SPI to bypass parent delegate, which, if we look at the source code, is to get the thread context classloader

Spi demo

A simple demonstration of how SPI is used without explaining it in detail (since it is not the focus of this article)

Write an arbitrary interface

Write a random implementation class

Create a new file in this directory with the fully qualified class name of the interface and the fully qualified class name of the implementation class.

Just test it out

That’s all for this time. Goodbye.