Some of the content comes from the following Blogs:
https://www.cnblogs.com/jhxxb/p/10900405.html
https://www.cnblogs.com/lzq210288246/p/13067904.html
Class 1 loader
1.1 what is it
The location of the class loader in the Java virtual machine is shown in the figure below:
Class loader is a code module that loads the binary byte stream of a class through the full class name of the class. Its main function is to put the binary data of the class file into the method area, and then create a class type object in the heap. The class object encapsulates the data structure of the class in the method area, and provides the developer with an interface to access the data structure in the method area.
1.2 uniqueness of class
For any class, its uniqueness in the Java virtual machine needs to be established by the class loader and the class itself.
Even if two classes come from the same Class file and are loaded by the same virtual machine, as long as the Class loaders that load them are different, the two classes are not equal.
The equality referred to here includes the return results of the equals() method, isAssignableFrom() method and isInstance() method of the Class object representing the Class, as well as the determination of the object's ownership relationship using the instanceof keyword.
2 classification
2.1 startup
Bootstrap classloader is responsible for loading the class libraries stored in the lib directory under the JDK installation directory, or the class libraries in the path specified by the - Xbootclasspath parameter (such as rt.jar, all classes beginning with java are loaded by bootstrap classloader).
The startup class loader cannot be directly referenced by the program, that is, it cannot be obtained directly.
2.2 extension class
ExtensionClassLoader, implemented by sun.misc.Launcher$ExtClassLoader, is responsible for loading the class libraries in the EXT directory under the JDK installation directory, or the class libraries in the path specified by the java.ext.dirs system variable (such as classes beginning with javax).
Developers can use the extension class loader directly.
2.3 Application
ApplicationClassLoader, implemented by sun.misc.Launcher$AppClassLoader, is responsible for loading the classes specified by the user ClassPath.
Developers can directly use the application class loader. If their own class loader has not been customized in the application, it is generally the default class loader in the application.
3 get
3.1 principle
Get system class loader (available):
ClassLoader.getSystemClassLoader(); Thread.currentThread().getContextClassLoader();
Get extension class loader (available):
ClassLoader.getSystemClassLoader().getParent();
Get boot class loader (not available):
ClassLoader.getSystemClassLoader().getParent().getParent();
3.2 testing
The test code is as follows:
public static void main(String[] args) { // Get system class loader ClassLoader appClassLoader = ClassLoader.getSystemClassLoader(); System.out.println(appClassLoader); // Get extension class loader ClassLoader extClassLoader = appClassLoader.getParent(); System.out.println(extClassLoader); // Get boot class loader ClassLoader bootClassLoader = extClassLoader.getParent(); System.out.println(bootClassLoader); // The custom class uses the system class loader System.out.println(ClassLoaderTest.class.getClassLoader()); // The classes provided by JDK use the boot class loader System.out.println(String.class.getClassLoader()); }
The operation results are as follows:
sun.misc.Launcher$AppClassLoader@18b4aac2 sun.misc.Launcher$ExtClassLoader@6d9c638 null sun.misc.Launcher$AppClassLoader@18b4aac2 null
3.3 relationship
The relationship between the three class loaders is shown in the figure below:
Here, the parent-child relationship between class loaders is generally not implemented by Inheritance relationship, but uses Composition relationship to reuse the code of the parent loader.
4 loading mechanism
4.1 overall responsibility
When a Class loader is responsible for loading a Class, other classes that the Class depends on and references will also be loaded by the Class loader, unless it is shown that another Class loader is used for loading.
4.2 parental delegation
First, let the parent class loader try to load the class. If there is a loader above the parent class loader, further delegate upward. Only when the parent class loader cannot load the class, try to load the class from its own class path.
4.3 caching mechanism
The caching mechanism will ensure that all loaded classes will be cached. When a Class needs to be used in the program, the Class loader first looks for the Class from the cache. Only if the cache does not exist, the system will read the binary data corresponding to the Class, convert it into a Class object and store it in the cache.
This is why after modifying the Class, the virtual machine must be restarted before the program modification will take effect.
5 parental delegation mechanism
5.1 significance
Avoid repeated loading of classes and ensure the global uniqueness of a class.
Ensure the safe and stable operation of the program and prevent the core classes from being tampered with at will.
5.2 damage
Parent delegation has been destroyed on three large scales.
5.2.1 code of damage before the introduction of parent delegation
Class loader and abstract class ClassLoader have existed since JDK 1.0. Parental delegation was introduced after JDK 1.2, adding a new method findClass().
Before that, the only purpose for users to inherit the ClassLoader class is to override the loadClass() method, and the specific logic of parental delegation is implemented in this method.
After JDK1.2, users are no longer encouraged to override the loadClass() method, but should write their own class loading logic into the findClass() method, so as to ensure that the newly written class loader complies with the parental delegation rules.
5.2.2 the basic class cannot load the code provided by the user
Parent delegation solves the problem of unifying the basic classes of various class loaders. The more basic classes are loaded by the upper loader, but if the basic class needs to call the user's code, it will cause new problems.
For example, JNDI service is now a standard service of Java. Its code is loaded by the startup class loader (rt.jar put in JDK1.3), but the purpose of JNDI is to centrally manage and find resources. It needs to call the code of JNDI interface provider (SPI, Service Provider Interface) implemented by independent manufacturers and deployed under the ClassPath of the application, However, the startup class loader can only load the basic class and cannot load the user class.
To this end, Java introduces Thread Context ClassLoader. This class loader can be set through the thread. Setcontextclassloader() method. If it is not set when creating a thread, it will inherit one from the parent thread. If it is not set in the global scope of the application, this class loader is the application class loader by default.
In this way, the JNDI service uses this thread context class loader to load the required SPI code, that is, the parent class loader requests the child class loader to complete the class loading action. This behavior actually opens up the hierarchy of parent delegation and uses the class loader in reverse, which has actually violated the general principle of parent delegation, But this is also a helpless thing. All SPI related loading actions in Java basically adopt this method, such as JNDI, JDBC, JCE, JAXB, JBI, etc.
5.2.3 users' pursuit of program dynamics
Code Hot Swap, module Hot Deployment, etc.
The key to the modular hot deployment of OSGi is the implementation of its custom class loader mechanism. Each program module (Bundle) has its own class loader. When a Bundle needs to be replaced, the Bundle and similar loaders will be replaced together to realize the hot replacement of code. In OSGi environment, class loader is no longer a tree structure in parental delegation, but further developed into a more complex mesh structure.
6 sandbox security mechanism
6.1 what is it
The core of the Java security model is the Java sandbox.
Sandbox is an environment that restricts program running. Sandbox mechanism is to limit Java code to the specific running range of virtual machine, and strictly restrict code access to local system resources. Such measures can ensure effective isolation of code and prevent damage to local system.
Sandboxes mainly restrict system resource access. Sandboxes at different levels can also restrict system resource access differently. System resources include CPU, memory, file system, network, etc.
6.2 safety model
The basic components that make up the Java sandbox:
1) Class, especially parent delegation.
2) Class file validation, that is, class file validator.
3) Security features built into the Java virtual machine (and language).
4) Security manager and API.
The security features of the first three parts of the Java security model work together to achieve a common purpose, maintaining the internal integrity of the instance of the Java virtual machine and its running application, so that they are not infringed by the downloaded malicious code.
On the contrary, the fourth component of the security model is the security manager, which is mainly used to protect the external resources of the virtual machine from malicious or vulnerable code running in the virtual machine. The security manager is a separate object. In the running Java virtual machine, it plays a central role in the access control of external resources.
6.3 examples
A String class is customized, but when loading the String class, the boot class loader will be used for loading, and the boot class loader loads the JDK's own String class during the loading process.
This can ensure the protection of Java core source code, protect program security and protect native JDK code to a certain extent.
7 custom class loader
7.1 requirements
Generally, most requirements can be met by directly using the system class loader, but sometimes you need to customize the class loader. For example, applications transmit Java class bytecodes through the network. In order to ensure security, these bytecodes are encrypted. At this time, the system class loader cannot load them, so it needs to be implemented by custom class loader.
7.2 steps
1) Inherit ClassLoader abstract class
AppClassLoader and ExtClassLoader are both static internal classes of Launcher, and their access permissions are the default package access permissions.
2) Override the findClass() method of the parent class
When all parent class loaders cannot be loaded, the loadCalss() method of JDK will call its own findClass() method to load the class.
7.3 codes
7.3.1 simulated loaded classes
Simulate a loaded simple class:
//Stored in the root directory of disk D public class DemoBusiness { public static void business() { ClassLoader classLoader = DemoBusiness.class.getClassLoader(); System.out.println("ClassLoader >>> " + classLoader); System.out.println("ClassLoader.parent >>> " + classLoader.getParent()); } }
In order not to be loaded by the application class loader, put the simple class in the root directory of disk D.
7.3.2 compiling loaded classes
Compile the Java code of a simple class and generate a class bytecode file:
D:\>javac -encoding utf8 DemoBusiness.java
7.3.3 custom class loader
The code is as follows:
public class DemoClassLoader extends ClassLoader { protected Class<?> findClass(String name) throws ClassNotFoundException { // Loads the Class with the specified Class name String classDir = "D:\\" + name.replace('.', File.separatorChar) + ".class"; byte[] classData = loadClassData(classDir); if (classData == null) { throw new ClassNotFoundException(); } else { return defineClass(name, classData, 0, classData.length); } } private byte[] loadClassData(String path) { try (InputStream ins = new FileInputStream(path); ByteArrayOutputStream baos = new ByteArrayOutputStream()) { int bufferSize = 4096; byte[] buffer = new byte[bufferSize]; int length = 0; while ((length = ins.read(buffer)) != -1) { baos.write(buffer, 0, length); } return baos.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return null; } }
7.3.4 testing
code:
public class DemoTest { public static void main(String[] args) throws Exception { // Specifies the class loader load call DemoClassLoader classLoader = new DemoClassLoader(); classLoader.loadClass("DemoBusiness").getMethod("business").invoke(null); } }
7.3.5 operation results
The results are as follows:
ClassLoader >>> com.demo.classloader.DemoClassLoader@1ee0005 ClassLoader.parent >>> sun.misc.Launcher$AppClassLoader@18b4aac2
Life cycle of category 8
8.1 introduction
Class starts from being loaded into the virtual machine memory to unloading the memory. Its whole life cycle includes five stages: loading, connecting, initializing, using and unloading.
As shown in the figure:
The connection includes three stages: verification, preparation and parsing. In some cases, the parsing phase can start after initialization to support the runtime binding of the Java language.
It is also noted that several stages here start in sequence rather than in sequence, because these stages are usually intermixed and usually invoke or activate another stage in the execution of a phase.
8.2 loading phase
8.2.1 what is it
Class loading is to read the binary data in the class file into the runtime memory, put the class information in the class file in the method area, and then create a class object in the heap to encapsulate the data structure in the method area.
8.2.2 what to do
When loading, the virtual machine needs to complete three things:
1) Get the binary byte stream of the class through the full class name of the class.
2) The static structure represented by the binary byte stream is transformed into the runtime data structure of the method area.
3) Create a Class object representing this Class in memory as an access to various data of this Class in the method area.
8.2.3 when
The virtual machine specification allows a class to load in advance when it is expected to be used, without waiting until a class is used for the first time.
If the class file is missing during class loading, the class loader will report an error only when the class is used. If the class is not used, the class loader will not report an error.
8.2.4 source of documents
1) Load directly from the local hard disk.
2) Download the class file and load it through the network.
3) Extract the class file from the compressed file and load it.
4) Extract the load from the database.
5) Compile the source file into a class file and load it.
8.2.5 supplementary instructions
Compared with other stages of class loading, the loading stage (specifically, the action of obtaining the binary byte stream of the class in the loading stage) is the most controllable stage, because developers can use either the class loader provided by the system to complete the loading or the custom class loader to complete the loading.
8.3 verification phase
8.3.1 what to do
Ensure that the information contained in the byte stream of the class file meets the requirements of the current virtual machine and will not endanger the security of the virtual machine itself.
The verification stage will roughly complete the inspection actions in four stages:
1) File format verification: verify whether the byte stream conforms to the specification of class file format. For example: whether it starts with 0xCAFEBABE, whether the major and minor version numbers are within the processing range of the current virtual machine, and whether the constants in the constant pool have unsupported types.
2) Metadata verification: analyze the information described by bytecode to ensure that the information described meets the requirements of Java language specification. For example, whether this class has superclasses other than Object.
3) Bytecode verification: through data flow and control flow analysis, it is determined that the program semantics is safe and logical, and will not lead to virtual machine crash.
4) Symbol reference verification: ensure that the parsing action can be executed correctly.
8.3.2 supplementary instructions
The verification phase is very important, but not necessary. It has no impact on the program running time. If the referenced class has been verified repeatedly, you can consider using the - Xverifynone parameter to close most class verification measures to shorten the time of virtual machine class loading.
8.4 preparation stage
8.4.1 what to do
The stage of allocating memory and setting initial values for class variables (that is, static member variables, excluding instance variables). The memory used by these variables is allocated in the method area.
Note that the preparation stage is only for static member variables. Generally, this stage only sets the initial value, not assignment. The assignment of static member variables is completed in the cinit method in the initialization stage.
In some cases, if the static member variable is also a constant and the assignment does not involve method calls (including construction method calls), the assignment will be performed at this stage.
8.4.2 supplementary instructions
For variables of non static type, the assignment is completed in the init method in the initialization phase.
static variables, but not final variables. Setting the initial value is completed in the preparation phase, and the assignment is completed in the cinit method in the initialization phase.
Variables of static type are variables of final type, and the assignment does not involve method calls. The assignment is completed in the preparation phase.
give an example:
// Set the initial value to 0 in the preparation phase and assign value in the clinit method in the initialization phase public static int i = 1; // Assignment in preparation phase public static final int INT_CONSTANT = 1; // Set the initial value to null in the preparation phase and assign a value in the clinit method in the initialization phase public static final Integer INTEGER_CONSTANT=Integer.valueOf(1); // Assignment in preparation phase public static final String STR = "hello"; // Set the initial value to null in the preparation phase and assign a value in the clinit method in the initialization phase public static final String STR_CONSTANT = new String("hello");
8.4.3 interface description
The attributes in the interface are decorated by static type and final type, so the assignment has been completed in the preparation stage.
8.5 analysis stage
8.5.1 what to do
The virtual machine replaces the symbolic reference in the constant pool with a direct reference, which will load all other classes referenced by this class. The reference methods in the class include inheritance, implementation interface, domain variable, method definition, local variable defined in the method, etc.
The parsing action mainly refers to class or interface, field, class method, interface method, method type, method handle and call point qualifier.
8.5.2 symbol reference
When compiling java files, Java classes do not know the actual address of the referenced class, so they can only use symbolic references instead.
8.5.3 direct reference
A pointer that points directly to the target (to the method area, Class object), to the relative offset (to the heap area, Class instance object), or to a handle that can indirectly locate the target.
8.6 initialization
8.6.1 what to do
Give the correct initial value to the static variables of the class. The virtual machine is responsible for initializing the class, mainly initializing the class variables.
There are two ways to set the initial value of class variables in Java:
1) Specifies the initial value when declaring a class variable.
2) Use static code blocks to specify initial values for class variables.
In other words, the initialization phase is the process of executing the cinit method of the class constructor.
If the class to be initialized has a parent class, the virtual opportunity ensures that the cinit method of the parent class has been executed before executing the cinit method of the child class.
8.6.2 thread safety
When the cinit method is executed, the virtual opportunity ensures the correct locking and synchronization in the multithreaded environment. If multiple threads initialize a class at the same time, only one thread will execute the clinit method of this class.
If there are time-consuming operations in the cinit method of a class, it may cause multithread blocking, resulting in deadlock, and this kind of deadlock is difficult to find, because it seems that they have no available lock information.
8.6.3 init method and cinit method
init is an object constructor method, that is, a method that is executed only when an object is new and the constructor of the class is called, which is used to assign values to non static variables.
clinit is a class constructor method, that is, a method called in the initialization phase of the class life cycle in the virtual machine, which is used to assign values to static variables.
For example:
class X { static Log log = LogFactory.getLog(); // <clinit> private int x = 1; // <init> X () { // <init> } static { // <clinit> } }
8.6.4 when
Class initialization occurs only when a class is actively used. Active use of a class includes the following six types:
1) Creating an instance of a class, including using new, reflection, cloning and serialization, will trigger initialization.
2) Accessing or assigning a value to a static variable of a class or interface will trigger initialization.
3) Calling a static method of a class triggers initialization.
4) As a parent class, initialization is triggered when a child class is initialized.
5) Class contains the main() method as the main class. Initialization will be triggered when the virtual machine is started
6) The dynamic language support provided by JDK1.7 involves parsing classes corresponding to relevant method handles. Initialization will be triggered when the virtual machine is started.
In addition, all other ways of referencing classes will not trigger initialization, which is called passive reference:
1) As a subclass, reference the static properties of the parent class
Referencing a static field of a parent class through a subclass does not result in subclass initialization. For static fields, only the class that directly defines the field will be initialized.
code:
class SuperClass { static { System.out.println("SuperClass init!"); } public static int value = 123; } class SubClass extends SuperClass { static { System.out.println("SubClass init!"); } } public class NotInitialization { public static void main(String[] args) { System.out.println(SubClass.value); // SuperClass init! } }
2) Reference a class through an array
Referencing a class through an array definition does not trigger the initialization of this class.
code:
class SuperClass { static { System.out.println("SuperClass init!"); } public static int value = 123; } public class NotInitialization { public static void main(String[] args) { SuperClass2[] superClasses = new SuperClass2[10]; } }
3) Constant of reference class
Constants are stored in the constant pool of the calling class at the compilation stage. In essence, they are not directly referenced to the class defining constants, so the initialization of the class defining constants will not be triggered.
code:
class ConstClass { static { System.out.println("ConstClass init!"); } public static final String HELLO_BINGO = "Hello Bingo"; } public class NotInitialization { public static void main(String[] args) { System.out.println(ConstClass.HELLO_BINGO); } }
8.6.5 interface description
Static code blocks cannot be used in the interface, but assignment operations of static variable initialization are allowed. Therefore, the interface will generate class construction methods as well as classes.
However, when the interface executes the class construction method, it does not need to load the parent interface, so it does not need to execute the class construction method of the parent interface in the preparation stage.
Only when the static variables of the parent interface are used, the parent interface will be loaded, and the class construction method of the parent interface will be executed in the preparation phase.
8.7 use stage
8.7.1 what to do
Call member variables or member methods to execute business logic.
8.8 unloading phase
8.8.1 what to do
The virtual machine unloads classes during garbage collection.
8.8.2 conditions met
All instances of this class have been recycled, that is, there are no instances of this class in the heap.
The ClassLoader that loaded this class has been recycled.
The Class object corresponding to this Class is not referenced anywhere, and the method of this Class cannot be accessed anywhere through reflection.
Loading sequence of class 9
9.1 regularity
When loading a class:
1) Load constants of basic types (including String types) modified by both static and final, and assign values. Completed in the preparation phase.
2) Load the static code of the parent class, including static code blocks and static variables, and give priority to the code written in front. Completed in initialization phase.
3) Load the static code of the class, including static code blocks and static variables, and give priority to the code written in front. Completed in initialization phase.
4) Load the member properties of the parent class, including construction code blocks and member variables, and give priority to the code written in front. Completed in initialization phase.
5) Loads the constructor method of the parent class. Completed in initialization phase.
6) Load the member properties of the class, including construction code blocks and member variables, and give priority to the code written in front. Completed in initialization phase.
7) Constructor method that loads the class. This step is completed in the initialization phase.
9.2 code
The test code is as follows:
public class Demo { public static void main(String[] args) throws Exception { new Person(); } } class Person extends Human { public PersonOther personOther = new PersonOther(); public static PersonOtherStatic personOtherStatic = new PersonOtherStatic(); public Person() { super(); System.out.println("Person constructor ..."); } { System.out.println("Person Common code block ..."); } static { System.out.println("Person Static code block ..."); } } class Human { public static HumanOtherStatic humanOtherStatic = new HumanOtherStatic(); public Human() { super(); System.out.println("Human constructor ..."); } { System.out.println("Human Common code block ..."); } static { System.out.println("Human Static code block ..."); } } class PersonOther { public PersonOther() { super(); System.out.println("PersonOther constructor ..."); } { System.out.println("PersonOther Common code block ..."); } static { System.out.println("PersonOther Static code block ..."); } } class PersonOtherStatic { public PersonOtherStatic() { super(); System.out.println("PersonOtherStatic constructor ..."); } { System.out.println("PersonOtherStatic Common code block ..."); } static { System.out.println("PersonOtherStatic Static code block ..."); } } class HumanOtherStatic { public HumanOtherStatic() { super(); System.out.println("HumanOtherStatic constructor ..."); } { System.out.println("HumanOtherStatic Common code block ..."); } static { System.out.println("HumanOtherStatic Static code block ..."); } }
The results are as follows:
HumanOtherStatic Static code block ... HumanOtherStatic Common code block ... HumanOtherStatic constructor ... Human Static code block ... PersonOtherStatic Static code block ... PersonOtherStatic Common code block ... PersonOtherStatic constructor ... Person Static code block ... Human Common code block ... Human constructor ... PersonOther Static code block ... PersonOther Common code block ... PersonOther constructor ... Person Common code block ... Person constructor ...
10 what is the difference between the forname () method and the loadClass() method
10.1 forName() method
This will cause the class to be actively loaded.
Class.forName() is a static method that returns a class object according to the passed in full class name.
This method will initialize the Class while loading the Class file into memory.
10.2 loadClass() method
Does not cause the class to be actively loaded.
ClassLoader.loadClass() is an instance method. It needs a ClassLoader object to call this method and load the class into memory according to the passed in full class name.
When this method loads the Class file into memory, it does not initialize the Class until it is used for the first time.