In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly explains "how to master the relevant knowledge points of class loaders". The content of the explanation in this article is simple and clear, and it is easy to learn and understand. let's study and learn "how to master the relevant knowledge points of class loaders"!
1. Overview of memory structure
If you want to write a Java virtual machine by hand, what are the main structures to consider?
Class loader
Executive engine
Complete block diagram:
2. Class loading subsystem
The role of class loader subsystem
The classloader subsystem is responsible for loading Class files from the file system or network, and the class file has a specific file identity at the beginning of the file.
ClassLoader is only responsible for loading the class file, and it is up to Execution Engine to decide whether it can run or not.
The loaded class information is stored in a memory space called the method area. In addition to class information, the method area also stores runtime constant pool information, which may also include string literals and numeric constants (this constant information is the memory mapping of the constant pool part of the Class file)
Class-- > Java.lang.Class
Class file exists on the local hard disk and can be understood as a template drawn by a designer on paper, and eventually the template is loaded into JVM to produce n identical instances based on the file instance.
The class file is loaded into the JVM, called the DNA metadata template, and placed in the method area.
In the .class file-> JVM- > eventually becomes a metadata template, and this process requires a transport (classloader Class Loader) to play the role of a courier.
3. Class loading process 3.1. Overview of class loading process.
Look at the code.
Public class HelloLoader {public static void main (String [] args) {System.out.println ("Thank ClassLoader for loading me"); System.out.println ("your great kindness, I'll report again in my next life!") ;}}
What is the loading process?
To execute the main () method (static method), you need to load the bearer class HelloLoader first
If the load is successful, link, initialize and other operations will be performed, and then the static method main in the HelloLoader class will be called.
If loading fails, an exception is thrown.
The complete flow chart is as follows: * load-> link (verify-- > prepare-- > parse)-- > initialize.
3.2. Loading phase
Loading process
Get the binary byte stream that defines this class through the fully qualified name of a class
Convert the static storage structure represented by this byte stream into the runtime data structure of the method area
Generate a java.lang.Class object representing this class in memory as an access entry for all kinds of data of this class in the method area
How to load class files
Load directly from the local system
Obtained through the network, typical scenario: Web Applet
Read from zip compressed package and become the basis of jar and war format in the future.
Run-time computing generation, the most commonly used is: dynamic agent technology
Generated by other files, typical scenario: it is rare for JSP applications to extract .class files from proprietary databases.
Typical protective measures against decompilation of Class files obtained from encrypted files
3.3. Link Pha
* links are divided into three sub-phases: verification-- > preparation-- > parsing.
3.3.1. Verification (Verify)
Verification
The purpose is to ensure that the byte stream of the Class file contains information that meets the requirements of the current virtual machine, ensures the correctness of the loaded classes, and does not endanger the security of the virtual machine itself.
It mainly includes four kinds of verification, file format verification, metadata verification, bytecode verification, symbol reference verification.
Give an example
Use BinaryViewer to view the bytecode file, which begins with CAFE BABE. If an illegal bytecode file appears, the verification will fail.
3.3.2. Prepare (Prepare)
Prepare for
Allocate memory for the class variable and set the default initial value of the class variable, that is, zero
Static decorated with final is not included here, because final assigns default values at compile time, and the preparation phase explicitly initializes
Note: initialization is not assigned to instance variables, class variables are assigned in the method area, and instance variables are assigned to the Java heap along with the object
Give an example
Code: the variable an is assigned an initial value in the preparation phase, but not 1, but 0, and is assigned to 1 in the initialization phase
Public class HelloApp {private static int a = 1; public static void main (String [] args) {System.out.println (a);}} 3.3.3, Resolve
Analysis
The process of converting symbolic references within a constant pool to direct references
In fact, parsing operations are often accompanied by JVM after initialization.
A symbolic reference is a set of symbols that describe the referenced target. The literal form of symbolic references is clearly defined in the class file format of the java virtual machine specification. A direct reference is a pointer directly to the target, a relative offset, or a handle that indirectly locates to the target.
Parsing actions are mainly aimed at classes or interfaces, fields, class methods, interface methods, method types, and so on. Corresponding to CONSTANT Class info, CONSTANT Fieldref info, CONSTANT Methodref info and so on in constant pool
Symbol reference
You can view symbol references after decompiling the class file
3.4. Initialization phase
Initialization phase
The initialization phase is the process of executing the class constructor method ().
This method does not need to be defined and is the result of the combination of the assignment action of all class variables in the class automatically collected by the javac compiler and the statements in the static code block. That is, when our code contains the static variable, there will be a clinit method
The instructions in the * * () method are executed in the order in which the statements appear in the source file * *
() A constructor that is different from a class. (correlation: the constructor is () from a virtual machine perspective)
If the class has a parent class, JVM ensures that the parent class () has been executed before the () execution of the subclass
The virtual machine must ensure that the () method of a class is locked synchronously under multithreading
Install the JClassLib plug-in in IDEA
Restart IDEA takes effect after installing the JClassLib plug-in in IDEA
Select the corresponding Java class file, note: it is not a bytecode file ~!
Click [View-- > Show Bytecode With jclasslib] to view the decompiled code
When we include the static variable in our code, there is a clinit method
Example 1: no static variable
Code
Public class ClinitTest {private int a = 1; public static void main (String [] args) {int b = 2;}}
No clinit method is generated
Example 2: have static variable
Code
Public class ClinitTest {private int a = 1; private static int c = 3; public static void main (String [] args) {int b = 2;}}
Initialize the static variable in the clinit method with a value of 3
Instructions in constructor methods are executed in the order in which statements appear in the source file
Example 1
Code:
Public class ClassInitTest {private static int num = 1; private static int number = 10; static {num = 2; number = 20; System.out.println (num);} public static void main (String [] args) {System.out.println (ClassInitTest.num); System.out.println (ClassInitTest.number);}}
The value of the static variable number changes as follows
During the preparation phase: 0
Perform static variable initialization: 10
Execute static code block: 20
Example 1
Code
Public class ClassInitTest {private static int num = 1; static {num = 2; number = 20; System.out.println (num);} private static int number = 10; public static void main (String [] args) {System.out.println (ClassInitTest.num); System.out.println (ClassInitTest.number);}}
The value of the static variable number changes as follows
During the preparation phase: 0
Execute static code block: 20
Perform static variable initialization: 10
The constructor is from the perspective of virtual machine ()
Code
Public class ClinitTest {private int a = 1; private static int c = 3; public static void main (String [] args) {int b = 2;} public ClinitTest () {a = 10; int d = 20;}}
In the constructor:
First assign the class variable a to 10
Then assign the local variable to 20
If the class has a parent class, JVM ensures that the parent class () has been executed before the () execution of the subclass
Code
Public class ClinitTest1 {static class Father {public static int A = 1; static {A = 2;}} static class Son extends Father {public static int B = A;} public static void main (String [] args) {System.out.println (Son.B);}}
As in the above code, the loading process is as follows:
First, to execute the main () method, you need to load the ClinitTest1 class
To get the Son.B static variable, you need to load the Son class
The parent class of the Son class is the Father class, so you need to load the Father class before the Son class.
The virtual machine must ensure that the () method of a class is locked synchronously under multithreading
Code
Public class DeadThreadTest {public static void main (String [] args) {Runnable r = ()-> {System.out.println (Thread.currentThread (). GetName () + "start"); DeadThread dead = new DeadThread (); System.out.println (Thread.currentThread (). GetName () + "end");}; Thread T1 = new Thread (r, "Thread 1") Thread T2 = new Thread (r, "Thread 2"); t1.start (); t2.start ();}} class DeadThread {static {if (true) {System.out.println (Thread.currentThread (). GetName () + "initialize the current class"); while (true) {}
The program is stuck, analyze the reason:
Two threads load the DeadThread class at the same time, and there is an endless loop in the static block of code in the DeadThread class
The thread that loads the DeadThread class first grabs the synchronization lock and then executes an endless loop in the class's static code block, while another thread is waiting for the synchronization lock to be released
So no matter which thread performs the loading of the DeadThread class first, the other class will not continue to execute.
4. Class loader classification 4.1, class loader overview
Classification of class loaders
JVM supports two types of classloaders. They are bootstrap class loader (Bootstrap ClassLoader) and custom class loader (User-Defined ClassLoader).
Conceptually, a custom class loader generally refers to a class of class loaders customized by developers in a program, but the Java virtual machine specification does not define it this way. Instead, all class loaders derived from the abstract class ClassLoader are divided into custom class loaders.
Regardless of the type of class loader, there are always only three of our most common class loaders in the program, as shown below
The relationship between the four here is an inclusive relationship, not the upper and lower levels, nor the inheritance of the child parent class.
Why both ExtClassLoader and AppClassLoader belong to custom loaders
Specification definition: all class loaders derived from the abstract class ClassLoader are divided into custom class loaders
ExtClassLoader inheritance tree
AppClassLoader inheritance tree
Code:
We try to get the bootstrap classloader with a value of null, which does not mean that the bootstrap classloader does not exist, because we cannot get the bootstrap classloader right-hand Cripple + language.
The value of the system class loader is the same twice: sun.misc.Launcher$AppClassLoader@18b4aac2, which means that * the system class loader is globally unique
Public class ClassLoaderTest {public static void main (String [] args) {ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader (); System.out.println (systemClassLoader); ClassLoader extClassLoader = systemClassLoader.getParent (); System.out.println (extClassLoader); ClassLoader bootstrapClassLoader = extClassLoader.getParent (); System.out.println (bootstrapClassLoader); ClassLoader classLoader = ClassLoaderTest.class.getClassLoader (); System.out.println (classLoader) ClassLoader classLoader1 = String.class.getClassLoader (); System.out.println (classLoader1);}} 4.2, loader with virtual machine 4.2.1, boot class loader
Boot classloader (bootstrap classloader, Bootstrap ClassLoader)
This class is loaded using the Cmax Cobb + language and is nested within JVM.
It is used to load Java's core library (content under the JAVA_HOME/jre/lib/rt.jar, resources.jar, or sun.boot.class.path path) and to provide classes needed by JVM itself.
Does not inherit from java.lang.ClassLoader and has no parent loader
Load the extension class and application class loader and act as their parent class loader (as their father)
For security reasons, the Bootstrap startup classloader only loads classes whose package names begin with java, javax, sun, etc.
4.2.2, extended class loader
Extended class loader (Extension ClassLoader)
Written in Java language and implemented by sun.misc.Launcher$ExtClassLoader
Derived from the ClassLoader class
The parent class loader is the startup class loader
Load the class library from the directory specified by the java.ext.dirs system properties, or from the jre/lib/ extsubdirectory (extension directory) of the JDK installation directory. If the user-created JAR is placed in this directory, it will also be automatically loaded by the extension class loader
4.2.3, system class loader
Application class loader (system class loader, AppClassLoader)
Written in Java language and implemented by sun.misc.LaunchersAppClassLoader
Derived from the ClassLoader class
The parent class loader is the extended class loader
It is responsible for loading the class library under the path specified by the environment variable classpath or the system attribute java.class.path.
This kind of loading is the default class loader in the program. Generally speaking, it completes the loading of classes applied by Java.
This kind of loader can be obtained by the classLoader.getSystemclassLoader () method.
Code example
Code
Public class ClassLoaderTest1 {public static void main (String [] args) {System.out.println ("* launch classloader *"); URL [] urLs = sun.misc.Launcher.getBootstrapClassPath () .getURLs (); for (URL element: urLs) {System.out.println (element.toExternalForm ()) } ClassLoader classLoader = Provider.class.getClassLoader (); System.out.println (classLoader); System.out.println ("* extended classloader *"); String extDirs = System.getProperty ("java.ext.dirs"); for (String path: extDirs.split (";")) {System.out.println (path) } ClassLoader classLoader1 = CurveDB.class.getClassLoader (); System.out.println (classLoader1);}}
System.out.println (classLoader); output null, which proves once again that we cannot get the boot class loader
* start the classloader * file:/C:/Program%20Files/Java/jdk1.8.0_144/jre/lib/resources.jarfile:/C:/Program%20Files/Java/jdk1.8.0_144/jre/lib/rt.jarfile:/C:/Program%20Files/Java/jdk1.8.0_144/jre/lib/sunrsasign.jarfile:/C:/Program%20Files/Java/ Jdk1.8.0_144/jre/lib/jsse.jarfile:/C:/Program%20Files/Java/jdk1.8.0_144/jre/lib/jce.jarfile:/C:/Program%20Files/Java/jdk1.8.0_144/jre/lib/charsets.jarfile:/C:/Program%20Files/Java/jdk1.8.0_144/jre/lib/jfr.jarfile:/C:/Program%20Files/Java/jdk1.8.0_144/jre/classesnull* * extended class loader * C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ extC:\ WINDOWS\ Sun\ Java\ lib\ extsun.misc.Launcher$ExtClassLoader@7ea987ac4.3, User-defined class loader
Why do you need a custom classloader?
In the daily application development of Java, class loading is almost performed by the above three kinds of loaders. When necessary, we can also customize the class loader to customize the loading mode of the class. Then why do you need a custom classloader?
Isolated load class
Modify the way classes are loaded
Extended loading source
Prevent source code leakage
How do I customize the classloader?
Developers can implement their own class loaders by inheriting the abstract class java.lang.ClassLoader class to meet some special requirements.
Before JDK1.2, when customizing the classloader, the ClassLoader class was always inherited and the loadClass () method was overridden to implement the custom classloading class. But after JDK1.2, users are no longer advised to override the loadClass () method. Instead, it is suggested that the custom classloading logic be written in the findclass () method.
When writing a custom class loader, if you don't have too complex requirements, you can directly inherit the URIClassLoader class, so you can avoid writing the findclass () method and the way it gets the byte code stream, and make the custom class loader write more succinctly.
Code example
Public class CustomClassLoader extends ClassLoader {@ Override protected Class findClass (String name) throws ClassNotFoundException {try {byte [] result = getClassFromCustomPath (name); if (result = = null) {throw new FileNotFoundException ();} else {return defineClass (name, result, 0, result.length) } catch (FileNotFoundException e) {e.printStackTrace ();} throw new ClassNotFoundException (name);} private byte [] getClassFromCustomPath (String name) {return null;} public static void main (String [] args) {CustomClassLoader customClassLoader = new CustomClassLoader (); try {Class clazz = Class.forName ("One", true, customClassLoader) Object obj = clazz.newInstance (); System.out.println (obj.getClass (). GetClassLoader ());} catch (Exception e) {e.printStackTrace ();} 4.4, about ClassLoader
Introduction to the ClassLoader class
The ClassLoader class, which is an abstract class, and all subsequent classloaders inherit from ClassLoader (excluding startup classloaders)
Sun.misc.Launcher is an entry application for a java virtual machine.
Access to ClassLoader
Access to:
Code example:
Public class ClassLoaderTest2 {public static void main (String [] args) {try {ClassLoader classLoader = Class.forName ("java.lang.String") .getClassLoader (); System.out.println (classLoader); ClassLoader classLoader1 = Thread.currentThread () .getContextClassLoader (); System.out.println (classLoader1); ClassLoader classLoader2 = ClassLoader.getSystemClassLoader (); System.out.println (classLoader2) } catch (ClassNotFoundException e) {e.printStackTrace ();} nullsun.misc.Launcher$AppClassLoader@18b4aac2sun.misc.Launcher$AppClassLoader@18b4aac25, parent delegation mechanism 5.1, parent delegation mechanism principle
The principle of parental appointment mechanism
The Java virtual machine loads class files on demand, that is, when you need to use this class, it loads its class file into memory to generate class objects. And when loading the class file of a class, the Java virtual machine uses the parent delegation mode, that is, handing the request to the parent class, which is a task delegation mode.
If a class loader receives a class load request, it will not load it first, but delegate the request to the parent class loader to execute
If the parent class loader still has its parent class loader, it further delegates upward, recursively, and requests the startup class loader that will eventually reach the top level.
If the parent loader can complete the class loading task, it returns successfully, and if the parent loader cannot complete the loading task, the child loader will try to load it itself, which is the parent delegate mode.
The parent class loader assigns tasks down layer by layer. If the subclass loader can load, the class is loaded. If the load task is assigned to the system class loader, the class cannot be loaded, an exception is thrown.
5.2. Parent delegation mechanism code example
Code example
Example 1:
Code: we create a java.lang.String class ourselves and write a block of static code
Package java.lang;public class String {static {System.out.println ("I am the static code block of the custom String class");}}
Load the String class in another program to see if the loaded String class is the String class that comes with JDK or the String class that we wrote ourselves.
Public class StringTest {public static void main (String [] args) {java.lang.String str = new java.lang.String (); System.out.println ("hello,atguigu.com"); StringTest test = new StringTest (); System.out.println (test.getClass (). GetClassLoader ());}}
The program does not output the contents of our static code block, so you can see that what is still loaded is the String class that comes with JDK.
Example 2:
Code: the entire main () method in our own String class
Package java.lang;public class String {static {System.out.println ("I am the static code block of the custom String class");} public static void main (String [] args) {System.out.println ("hello,String");}}
Because the parent delegation mechanism finds the String class that comes with JDK, there is no main () method in that String class
Example 3:
Code: the entire ShkStart class under the java.lang package
Package java.lang;public class ShkStart {public static void main (String [] args) {System.out.println ("hello!");}}
For protection reasons, we are not allowed to customize classes under the java.lang package.
Example 4:
When we load jdbc.jar for database connections
The first thing we need to know is that jdbc.jar is implemented based on the SPI interface.
So when loading, parents delegate, eventually loading the SPI core class from the root loader, and then loading the SPI interface class
Then the reverse delegate is carried out and the loading of the class jdbc.jar is realized through the thread context class loader.
5.3. Advantages of parental appointment mechanism
Advantages of parental appointment mechanism
From the above example, we can see that the parental mechanism can
Avoid repeated loading of classes
Protect program security and prevent core API from being tampered with at will
Custom class: java.lang.String is useless
Custom class: java.lang.ShkStart (error: prevent the creation of classes at the beginning of java.lang)
6. Sandbox security mechanism
Custom String class: when loading a custom String class, it will be the first to use the bootstrap class loader to load, while the bootstrap class loader will first load the file that comes with jdk (java.lang.String.class in the rt.jar package). The error message says that there is no main method, just because what is loaded is the String class in the rt.jar package.
This ensures the protection of the core source code of java, which is the sandbox security mechanism.
7. Other
How can I tell if two class objects are the same?
There are two necessary conditions for indicating in JVM whether two class objects are the same class:
The full class name of the class must be the same, including the package name
The ClassLoader (the ClassLoader instance object) that loads this class must be the same
In other words, in JVM, even if the two class objects (class objects) come from the same Class file and are loaded by the same virtual machine, the two class objects are not equal as long as they are loaded with different ClassLoader instance objects.
Reference to the class loader
JVM must know whether a type is loaded by the boot loader or by the user class loader
If a type is loaded by a user class loader, JVM saves a reference to the class loader in the method area as part of the type information
When resolving references from one type to another, JVM needs to ensure that the class loaders of the two types are the same
Active and passive use of classes
Java programs use classes in two ways: active use and passive use. Active use can be divided into seven situations:
Create an instance of the class
Access the static variable of a class or interface, or assign a value to it
Call the static method of the class
Reflection (for example: Class.forName ("com.atguigu.Test"))
Initialize a subclass of a class
A class that is marked as a startup class when the Java virtual machine starts
JDK7 begins to provide dynamic language support: if the parsing result of java.lang.invoke.MethodHandle instance REF_getStatic, REF putStatic, REF_invokeStatic handle corresponding to the class is not initialized, initialize
Thank you for your reading. the above is the content of "how to master the relevant knowledge points of class loaders". After the study of this article, I believe you have a deeper understanding of how to master the relevant knowledge points of class loaders. The specific use of the situation also needs to be verified by practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.