Learning the JVM from Scratch series:

Learning from the Ground up ->JVM (Preface)

Learning from the ground up ->JVM (Preface) – Why delay?

JVM (a) : The Java Memory Model (JMM) is not the Java Virtual Machine memory model (JVM) oh!

Learning from the Ground up – JVM part 2: Why does Java Need a JVM (Java Virtual Machine)?

Learning from the Ground up ->JVM (3) : Classloader (1)

Learning from the Ground up ->JVM (4) : Classloader (Middle)

Learning from the ground up ->JVM (5) : Classloader (2)

Learning from the Ground up – JVM part 6: The Relationship between threads and JVMS

Learning from the ground up ->JVM (7) : Runtime Data Area (1)

Learning from the ground up ->JVM (8) : Runtime Data area (2)

Learning from scratch ->JVM (9) : Garbage Collection (1)

Learning from the ground up ->JVM (10) : Garbage Collection (middle)

Learning from scratch ->JVM (11) : Garbage Collection (2)

preface

In our last article, “Learning the JVM from the Ground up: Class loaders (Part 4),” we knew the basics of class loaders, but we didn’t have a clear understanding of the underlying logic of class loaders.

We’re just aware of how many types of class loaders there are, how class loaders load the parent delegate model and how to break the parent delegate model and so on.

But what lies behind these principles?

When you think about it, the JVM itself is a conceptual creation, not a physical one, so the classloaders that are part of the JVM, and our classloading process, are just our conceptual division. And what underpins these conceptual divisions is our code. These codes, C++ code, Java code, these codes, combined into a closed logic, in reality, to achieve the principle and conceptual theory we want to achieve.

In today’s article, we will attempt to look at our classloader and some of the associated classloading mechanisms at the code level.

The body of the

1. The Launcher class

Since the BootStapClassLoader is written in C++ and is embedded in the JVM kernel, that is, it is not visible from the Java code level, so we won’t go into the boot class loader.

The first class generated by the JVM is the Launcher class, which looks like this:

public static void main(String[] args) { ClassLoader classLoader = Launcher.class.getClassLoader(); System.out.println(" loader: "+ classLoader); }Copy the code

The code runs as follows:

E:\ JDK \bin\java.exe loader: null Process finished with exit code 0Copy the code

Note that the final root loader prints null, which does not mean it is null, but just because the launcher class loader was written by C++, it is null in Java.

The result of the code run is null, which tells us that the class was loaded by the BootstrapClassLoader.

That is, the BootstrapClassLoader is generated when the JVM starts, and the BootrapClassLoader creates an instance of the Launcher class the first time the JVM starts.

So why create an instance of the Laucher class? Let’s start by looking at the code inside the Launcher class, which looks like this:

public class Launcher { private static URLStreamHandlerFactory factory = new Launcher.Factory(); private static Launcher launcher = new Launcher(); private static String bootClassPath = System.getProperty("sun.boot.class.path"); private ClassLoader loader; private static URLStreamHandler fileHandler; public static Launcher getLauncher() { return launcher; } public Launcher() { Launcher.ExtClassLoader var1; Try {/ / create ExtClassLoader loader var1 = the Launcher. ExtClassLoader. GetExtClassLoader (); } catch (IOException var10) { throw new InternalError("Could not create extension class loader", var10); } try {// Get the AppClassLoader setting as the default loader loader by creating an ExtClassLoader. / / and set AppClassLoader to default loader this. Loader. = the 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"); if (var2 ! = null) { SecurityManager var3 = null; if (!" ".equals(var2) && !" default".equals(var2)) { try { var3 = (SecurityManager)this.loader.loadClass(var2).newInstance(); } catch (IllegalAccessException var5) { ; } catch (InstantiationException var6) { ; } catch (ClassNotFoundException var7) { ; } catch (ClassCastException var8) { ; } } else { var3 = new SecurityManager(); } if (var3 == null) { throw new InternalError("Could not create SecurityManager: " + var2); } System.setSecurityManager(var3); }}}Copy the code

The Launcher class has a constructor called Launcher() that creates an ExtClassLoader when the Launcher is created. Create the AppClassLoader from the ExtClassLoader you created, and set the AppClassLoader as the default system loader (that is, the context classloader for the current thread).

Therefore, when we want to get the AppClassLoader for the current application, we can get it with the following code:

public static void main(String[] args) { ClassLoader classLoader = Launcher.getLauncher().getClassLoader(); System.out.println(" loader: "+ classLoader); }Copy the code

The running results are as follows:

E:\ JDK \bin\java.exe loader: sun.misc.Launcher$AppClassLoader@18b4aac2 Process finished with exit code 0Copy the code

Then, now that we have created the ExtClassLoader and AppClassLoader, we can look at the source code for these two loaders. Notice that both of these loaders are static inner classes of the Launcher class.

2. ExtclassLoader and AppClassLoader

ExtclassLoader:

Static class ExtClassLoader extends URLClassLoader  { public static Launcher.ExtClassLoader getExtClassLoader() throws IOException { final File[] var0 = getExtDirs(); try { return (Launcher.ExtClassLoader)AccessController.doPrivileged(new PrivilegedExceptionAction<Launcher.ExtClassLoader>() { public Launcher.ExtClassLoader run() throws IOException { int var1 = var0.length; for(int var2 = 0; var2 < var1; ++var2) { MetaIndex.registerDirectory(var0[var2]); } return new Launcher.ExtClassLoader(var0); }}); } catch (PrivilegedActionException var2) { throw (IOException)var2.getException(); }}}Copy the code

ExtclassLoader inherits the URLClassLoader class. URLClassLoader is an extension of the ClassLoader class.

Instead of overwriting the loadClass() method of the ClassLoader class, ExtclassLoader directly calls the loadClass() method of the top-level ClassLoader class.

AppClassLoader:

static class AppClassLoader extends URLClassLoader { final URLClassPath ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this); public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException { final String var1 = System.getProperty("java.class.path"); final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1); return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() { public Launcher.AppClassLoader run() { URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2); return new Launcher.AppClassLoader(var1x, var0); }}); } public Class<? > loadClass(String var1, boolean var2) throws ClassNotFoundException { int var3 = var1.lastIndexOf(46); if (var3 ! = -1) { SecurityManager var4 = System.getSecurityManager(); if (var4 ! = null) { var4.checkPackageAccess(var1.substring(0, var3)); } } if (this.ucp.knownToNotExist(var1)) { Class var5 = this.findLoadedClass(var1); if (var5 ! = null) { if (var2) { this.resolveClass(var5); } return var5; } else { throw new ClassNotFoundException(var1); } } else { return super.loadClass(var1, var2); }}}Copy the code

The AppclassLoader also inherits the URLClassLoader class.

AppclassLoader overrides the loadClass() method of the ClassLoader class.

3. URLClassLoader class inherited from ClassLoader

The java.net.URLClassLoader class is an extension of the ClassLoader class.

The ClassLoader can only load classes from the classpath, while the URLClassLoader can load classes from any path.

The class.forname () method is usually used to dynamically load classes, but this method can only create classes that are already referenced in the program and can only be indexed by methods with package names, such as java.lang.string. You cannot create a.class file or a class in a.jar package that is not in a program reference.

The URLClassLoader provides this functionality, which allows us to load in the following ways:

  1. File: (loaded from the file system directory)
  2. Jar package: (load from jar package)
  3. Http: (loaded from a remote Http service)

4. Abstract ClassLoader (top class)

Java.lang.ClassLoader is an abstraction of the ClassLoader at the Java level. This class standardizes the basic process of class loading and is the top class in class loading.

  1. Parent () : a reference to the parent class loader. A class loader usually saves a reference to the parent class loader to implement the parent delegate mechanism.
  2. The loadClass() method, which is the core method of the classloader that implements parent-delegate logic.

The code is as follows:

Public abstract class ClassLoader {private final ClassLoader parent; // Name is the name of the Class to load. Resolve is whether the Class resolves protected Class<? > loadClass(String name, Boolean resolve) throws ClassNotFoundException {synchronized (getClassLoadingLock(name)) {// First, check whether the Class has been loaded. > c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent ! C = parent.loadClass(name, false); c = parent.loadClass(name, false); C = findBootstrapClassOrNull(name); c = findBootstrapClassOrNull(name); }} catch (ClassNotFoundException e) { // From the non-null parent class loader} if (c == null) {long t1 = system.nanotime (); C = findClass(name); c = findClass(name); / / this is the defining class loader, record data sun. Misc. PerfCounter. GetParentDelegationTime (). The addTime (t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); ResolveClass (c); resolveClass(c); resolveClass(c); resolveClass(c); } // Return the corresponding Class object. }}}Copy the code

In this loadClass() method, most of the methods we call are native methods, which are written in C++ and cannot be implemented in Java.

As we can see from the above code, the parent delegate model of class loading mechanism is implemented.

5. Hierarchical relationships between loaders

For example, the parent of userClassLoader is AppClassLoader, and the parent of AppClassLoader is ExtClassLoader. The parent class loader of ExtClassLoader is BootStrapClassLoader, which is the highest class loader.

I’ll start with the following code:

Public static void main(String[] args) throws IOException {// obtain the application ClassLoader AppClassLoader ClassLoader AppClassLoader = ClassLoader.getSystemClassLoader(); System.out.println(" Application class loader: "+ appClassLoader); Enumeration<URL> enums = appClassLoader.getResources(""); While (enums.hasmoreElements ()) {system.out.println (" Application class loader loading path: "+ enums.nextelement ()); break; ClassLoader ExtClassLoader = appClassLoader.getparent (); System.out.println(" extClassLoader: "+ extClassLoader); System.out.println(" Extension class loader loading path: "+ System.getProperty("java.ext.dirs")); ClassLoader bootClassLoader = extClassloader.getparent (); System.out.println(" root class loader: "+ bootClassLoader); }Copy the code

This code runs as follows:

E:\ JDK \bin\java.exe Application class loader: sun.misc.Launcher$AppClassLoader@18b4aac2 Extension class loader: Sun.misc.Launcher$ExtClassLoader@156643d4 Root classloader: null Process finished with exit code 0Copy the code

So we can see that the result of running the program is the same as the result of what we want in our code. That is, indeed, as I said before, summed up as follows:

  1. The parent class loader of userClassLoader is AppClassLoader.
  2. The parent of AppClassLoader is ExtClassLoader.
  3. The parent class loader of ExtClassLoader is BootStrapClassLoader.
  4. The BootStrapClassLoader is the highest level class loader.
  5. AppClassLoader is the default class loader for your program.

6. Load path of the class loader

Based on the above code, let’s modify the code slightly:

Public static void main(String[] args){// Get the BootStrapClassLoader URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs(); For (URL URL: urls) {system.out.println ("BootstrapClassLoader: "+ URL); break; ExtClassLoader URLClassLoader ExtClassLoader = (URLClassLoader)ClassLoader.getSystemClassLoader().getParent(); urls = extClassLoader.getURLs(); For (URL URL: urls){system.out.println ("ExtClassLoader: "+ URL); break; } / / application (system) class loader AppClassLoader this AppClassLoader. = this getSystemClassLoader (); Enumeration<URL> enums = appClassLoader.getResources(""); While (enums.hasmoreElements ()) {system.out.println ("AppClassLoader loading path: "+ enums.nextelement ()); break; }}Copy the code

The resulting code runs as follows:

E:\ JDK \bin\java.exe BootstrapClassLoader is responsible for loading the <JAVA_HOME>\lib directory 2. Loading paths: file: E: / JDK/jre/lib/resources. The jar ExtClassLoader loading paths: File: E: / JDK/jre/lib/ext/access - bridge - 64. The jar AppClassLoader loading paths: file:/L:/order-service/order-service-web/target/classes/ Process finished with exit code 0Copy the code

Therefore, from the final result, we can obtain the loading path of these class loaders, summarized as follows:

  1. The BootstrapClassLoader is responsible for loading stored in the

    \lib directory
  2. ExtClassLoader is used to load extended classes in JAVA. The ExtClassLoader can load the class libraries from the java.ext.dirs directory or from the JDK installation directory: jre/lib/ext. It is a subclass of the start class loader.
  3. AppClassLoader loads the class libraries in the path specified by the environment variable classpath or system property java.class.path.

7. Write a UserClassLoader by hand

As we know, there are two ways to implement your own class loader, UserClassLoader:

  1. Inherit the java.lang.classloader class and override the findClass() method
  2. If you don’t have too complicated requirements, you can simply inherit the URLClassLoader class and override the loadClass method. See AppClassLoader and ExtClassLoader for details. (Note that this breaks the parental delegation model as I’ve illustrated in the screenshot above.)

The second solution, directly simulate AppClassLoader or ExtClassLoader source can be, we today, through the first solution, to hand write a UserClassLoader.

7.1 Creating a loader MyUserClassLoader

package com.blog.permission.classLoad; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; public class MyUserClassLoader extends ClassLoader{ private String rootPath; public MyUserClassLoader() { super(); } public MyUserClassLoader(String rootPath) { this.rootPath = rootPath; } /** * Used to find Class files * @param className Fully qualified name of Class files * @return * @throws ClassNotFoundException */ @override protected Class<? > findClass(String className) { Class<? > clz = findLoadedClass(className); if (clz ! = null) return clz; byte[] classData = loadClassData(className); clz = defineClass(className, classData, 0, classData.length); return clz; } /** * this is to convert the file to binary bytecode * @param className * @return */ private byte[] loadClassData(String className) {String pathName = rootPath + className.replace(".", "/") + ".class"; System.out.println(pathName); byte[] bytes = null; try (FileInputStream fis = new FileInputStream(pathName); ByteArrayOutputStream bos = new ByteArrayOutputStream();) { byte[] flush = new byte[1024 * 1024]; int len = -1; while (-1 ! = (len = fis.read(flush))) { bos.write(flush); } bytes = bos.toByteArray(); } catch (Exception e) {system.out.println (" Exception "); } return bytes; }}Copy the code

7.2 Creating a Java class to load: shuaige.java

package com.blog.permission.classLoad;


public class Shuaige {
    public static void main(String[] args) {
        System.out.println("I'm so cool,you underStand?");
    }
}
Copy the code

7.3 Compiling the shuaige. Java file to the shuaige. class file

7.4 Creating a running class

package com.blog.permission.classLoad;

public class TestClassLoad {

    public static void main(String[] args) throws ClassNotFoundException {
        MyUserClassLoader fileSystemClassLoader = new MyUserClassLoader("/com/blog/permission/classLoad");

        Class<?> c = fileSystemClassLoader.loadClass("com.blog.permission.classLoad.Shuaige");

        System.out.println(c);
    }
}
Copy the code

The resulting hierarchical directory is as follows:

7.5 The following results are obtained

E:\jdk\bin\java.exe 

class com.blog.permission.classLoad.Shuaige

Process finished with exit code 0
Copy the code

conclusion

Through the analysis and interpretation of the loader code, it is clear that we have gained a deeper understanding of the mechanism of class loading.

Of course, to some extent, the source code analysis of this article, but also the analysis of a part of it, there are many places are not involved. But through these source code, we have the class loader, the texture of the improvement, class loader and the class loading process, in our mind, is no longer a virtual concept does not fall into place, but really exist by the code to achieve things.

At this point, the whole reading of the class loader is over.

Refer to the blog

Blog.csdn.net/how_interes…

Blog.csdn.net/chuodan5158…

www.cnblogs.com/chinaifae/p…

Blog.csdn.net/weixin_3916…

www.cnblogs.com/rogge7/p/77…

Reference books

Understanding the Java Virtual Machine by Zhiming Zhou