Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to master the relevant knowledge points of class loaders

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.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report