Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”. This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

How does the Class file work

Two.Classloader source code process

1. How do I load class

ClassLoader (java.lang.ClassLoader#loadClass(String, Boolean))

Note:This parent is a member property of the ClassLoader, not a child/parent inheritance relationship

Conclusion:If the parent loader is null, BootstrapClassLoader is called to load the ClassLoader. After all parent loaders fail, the current ClassLoader overrides the findClass method to load the ClassLoader

1.1 presentation

We are writing a test class, UserService, and then creating another test class, new UserService() in the main method.

public static void main(String[] args) {
    debugLoadClass();
}
public static void debugLoadClass() {
    UserService userService = new UserService();
}
Copy the code

Then add a breakpoint to findLoadedClass and findClass of the loadClass methodname! =null&&name.indexOf("UserService")! = 1The dynamic diagram for debugging is shown below


  • Text Description:
    1. The UserService is first loaded by the loadClass method overwritten by AppClassLoader and then called by the loadClass method of the parent ClassLoader.
    2. The appClassloader. parent attribute is equal to ExtClassLoader, so ExtClassLoader tries to load it
    3. The parent property of ExtClassLoader is empty, so it is loaded by BootstrapClassLoader
    4. The BootstrapClassLoader cannot find the UserService return null, so the BootstrapClassLoader loads it to extClassloader.findClass
    5. Extclassloader.findclass could not find a ClassNotFoundException thrown by UserService, so it was loaded by AppClassLoader.findClass
    6. The appClassLoader.findClass load succeeded. Procedure

Question:

  1. Extclassloader. findClass(UserService) returns null, but AppClassLoader can find it

Conclusion: Each classLoader is only responsible for loading classes in a specific path, which path will be discussed below


  • LoadClass flowchart:

2. How is the classloader initialized

2.1 How are the three core classloaders initialized

The {@see sun.misc.Launcher} class is loaded by BootstrapClassLoader when the program starts. Since BootstrapClassLoader is not visible to Java, only the Launcher class is studied this time, and its constructor core code is as follows

Public Launcher() {// Create ExtClassLoader, And its parent property set to empty the Launcher. ExtClassLoader ExtClassLoader. = the Launcher ExtClassLoader. GetExtClassLoader (); / / AppClassLoader creation, and its parent attributes for extClassLoader enclosing loader. = the Launcher AppClassLoader. GetAppClassLoader (extClassLoader);  // set the class loader for the currentThread context to AppClassLoader thread.currentthread ().setcontextclassloader (this.loader); . }Copy the code

The data direction of the code is as follows

2.1 How is a custom class loader initialized

Custom classloaders generally inherit from the abstract ClassLoader class, so they must call the no-argument constructor java.lang.classloader #ClassLoader(), which sets the parent property of the current ClassLoader to AppClassLoader

Protected ClassLoader() {/** * The loader property of the Launcher object calls the ClassLoader constructor with no arguments, Assign the current classloader.parent property to this.loader * {@link ClassLoader#ClassLoader()} * (this(checkCreateClassLoader(), getSystemClassLoader());) * {@link ClassLoader#getSystemClassLoader()} * (scl = sun.misc.Launcher.getLauncher().getClassLoader();) * (return scl;) */ this(checkCreateClassLoader(), getSystemClassLoader()); }Copy the code

2. Why load the class like this

Why is the Java loadClass method so cumbersome to recursively load, simply use a loader?

2.1 advantages:

  1. Class objects are guaranteed to be unique (within the same ClassLoader chain)

Because it is loaded first by parent, it is guaranteed that a class will only be loaded once by a fixed class loader chain.

  1. Ensures isolation of class objects (under the same ClassLoader chain)

Since parent loads the same class first, and parent is determined by the current ClassLoader, if two different loaders load the same class, they get two different class objects.

So the unique identity of the class isClassloader. id+ Fully qualified class name(PackageName+ClassName), so if classLoader. id is different, the two instances cannot be cast even if their fully qualified class names are the same, such is the isolation of the JVM. Such as:

  1. Core libraries are consistent and not tampered with

The underlying core classes associated with the JDK (under the java.lang package, etc.) have already been loaded by the parent loader, so the child loader will not reload them.

It is also called when banishing the binary of the class file into the JVM method areajava.lang.ClassLoader#defineClass, which is final, validates, and if name begins with java.xxx, an error is reported

2.1 disadvantages:

  1. A strong parent delegate rule that prevents instances of the parent loader from using instances that can only be loaded by child loaders

The way to do that is to break the parental delegation mechanism. For example, the java.util.ServiceLoader SPI mechanism, BootstrapClassLoader loads the java.sql.Driver interface and java.sql.DriverManager class. Where DriverManager needs to get the concrete implementation class of the Driver to do some operations; The specific implementation classes are JAR packages provided by mysql, Orcale, etc. The loading path of BootstrapClassLoader does not include third-party jars introduced by users and can only be loaded by AppClassLoader or other custom class loaders. Solution: When the Class object of the Driver interface implementation Class needs to be initialized, Use AppClassLoader or another custom classloader to initialize class.forname (” Fully qualified Class name of the Driver interface implementation Class “,false,AppClassLoader or other custom classloader) AppClassLoader has only one static instance by default. You can obtain the instance in the following ways

1. {@link sun.misc.Launcher.getLauncher().loader}
2. {@link java.lang.ClassLoader.getSystemClassLoader()}
3. {@link Thread.currentThread().getContextClassLoader()}// May have been reset
Copy the code

The serviceloader.next method will eventually be calledjava.util.ServiceLoader.LazyIterator#nextServiceMethod to initialize the implementation class of the target interface configured for the META-INF/services path

  1. A class is loaded only once, which makes the scenario of multiple versions of the same class (coexistence of jar packages of multiple versions) impossible

Other questions

  1. Question: Why can IDEA debug the latest code without install after importing multiple projects

Jvm-utils-v1.0 was introduced into the existing jVM-utils-v1.0 project, and the jVM-utils-v1.0 is currently open, so let’s print java.class.path

Let’s change the current open JVM-utils to 2.0 and look at ava.class.path

    Conclusion:Import jar package path if in the current project,java.class.pathInstead of storing the jar package’s location in the Maven library, it will store the project’s compile path/target/classes; With each startup, IDEA recompiles the associated project, so you can run the latest code without install

4. To summarize

1. Class loader relationship

loader Loading paths The parent attribute
BootstrapClassLoader

Start the class loader
sun.boot.class.path

Core class library rt.jar, etc
There is no
ExtClassLoader

The loader is extended
java.ext.dirs

Extended class library DNSNS. Jar, etc
null

Indirection equals Bootstrap
AppClassLoader

Application loader
java.class.path

Current project working path, imported JAR package path, etc
ExtClassLoader
Reset parent’s loader Override findClass control The incoming parent
The loader that did not reset parent Override findClass control AppClassLoader

2. LoadClass flow chart