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