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")! = 1
The dynamic diagram for debugging is shown below
- Text Description:
- The UserService is first loaded by the loadClass method overwritten by AppClassLoader and then called by the loadClass method of the parent ClassLoader.
- The appClassloader. parent attribute is equal to ExtClassLoader, so ExtClassLoader tries to load it
- The parent property of ExtClassLoader is empty, so it is loaded by BootstrapClassLoader
- The BootstrapClassLoader cannot find the UserService return null, so the BootstrapClassLoader loads it to extClassloader.findClass
- Extclassloader.findclass could not find a ClassNotFoundException thrown by UserService, so it was loaded by AppClassLoader.findClass
- The appClassLoader.findClass load succeeded. Procedure
Question:
- 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:
- 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.
- 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:
- 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:
- 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#nextService
Method to initialize the implementation class of the target interface configured for the META-INF/services path
- 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
- 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.path
Instead 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 |