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

What is the Class Loader in the Art of JVM

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly introduces "what is the class loader of the art of JVM". In the daily operation, I believe that many people have doubts about what is the class loader of the art of JVM. The editor consulted all kinds of materials and sorted out simple and easy-to-use methods of operation. I hope it will be helpful to answer the questions of "what is the class loader of the art of JVM?" Next, please follow the editor to study!

What are defining class loaders and initializing class loaders?

Define a class loader: assuming that one of our classes is loaded by ExtClassLoader, then ExtClassLoader is called the definition class loader for that class

Initialization loader: the initial class loader that can return Class object references is called the class, for example, class An is loaded by our ExtClassLoader, then

ExtClassLoader is the definition class loader of the class and the initial class loader of the class, and our AppClassLoader can also return a reference to our class A.

Then AppClassLoader is also the initial class loader for this class.

What is the parent delegation model for classloaders?

In the last article, we mentioned the parent delegation model of the classloader, which can also be called the parent delegate model. In today's article, we will explain this concept clearly.

Concept: describe the concept of parental delegation in a simple way. Can be divided into two parts to understand

1 entrusting:

When jvm loads a class, it is delegated by its parents and delegated from the bottom up.

When the custom class loader needs to load the class, it first delegates the application class loader to load, then the application class loader delegates to the extended class loader, and the extended class loader delegates to the startup class loader.

If the startup class loader cannot load the class. Then load it down.

2 loading:

When jvm loads a class, it loads the delegate through its parents, but when it loads, it loads from top to bottom. When the delegate starts the classloader at the top level, it cannot delegate upwards, so

The startup class loader starts to try to load this class. If the startup class loader cannot load, it is handed down to the extended class loader to load. If the extended class loader cannot be loaded, it continues to delegate down to the application class loader.

To load, and so on.

If the text description you are not clear about what the parental delegation mechanism is, then I have drawn a picture to better understand the class loading process. As follows:

From the figure above, we know more clearly how the parental delegation model works, in a simple word, when you need to load a class, delegate up and load down.

Note: in the parent delegation mechanism, each loader forms a tree structure according to the parent-child relationship, and each loader has one and only one parent loader except the root loader.

Next, I also draw a picture of the main process of class loading from the point of view of the underlying source code of jdk, as shown below:

These are the important process steps for a class loader to load a class. I hope all the boys can combine the source code and study it carefully. It's actually quite understandable.

Let's talk about it again. What are the benefits of java using a parent delegate to load a class?

Benefits of the parental delegation model

It is well known that the java.lang.object class is the parent class of all classes, so our program loads the java.lang.object class into memory at run time, if the java.lang.object class

If it can be loaded by our custom class loader, then there will be multiple Object Class objects in jvm, and these Class objects are incompatible.

Therefore, the parent delegation model can ensure the type security under the java core class library.

With the help of the parent delegation model, the classes of our java core class library must be loaded by our startup class loader, which ensures that only one of our core class libraries exists in jvm

This will not give the custom class loader to load the classes of our core class library.

According to our demonstration, a class can be loaded by multiple classloaders, and there can be multiple different versions of Class objects in jvm memory that are incompatible.

And it can't be converted to each other.

What is full delegate loading?

Explanation: if our Person class is loaded by our system class APP class loader, and the Dog class on which the person class depends will also be delegated to the App system class for row loading, this delegation process also follows the parent delegation model. The code is as follows

Create a Dog instance in the person class code

Public class Person {

Public Person () {new Dog ();}

}

Public class Dog {public Dog () {System.out.println ("constructor of Dog");}}

Test class

Public class MainClass02 {public static void main (String [] args) throws Exception {/ / create an instance of the custom classloader and specify the name Test01ClassLoader myClassLoader = new Test01ClassLoader ("loader1") through the constructor; myClassLoader.setPath ("I:\ test\"); Class classz = myClassLoader.loadClass ("com.test.Person"); System.out.println (classz.getClassLoader ()) System.out.println (Dog.class.getClassLoader ());}} run result: sun.misc.Launcher$AppClassLoader@18b4aac2sun.misc.Launcher$AppClassLoader@18b4aac2Process finished with exit code 0

From the above running results, we can see that when we use the custom class loader to load our Person, according to the parent delegate model, our Person is not loaded by the custom class load (Test01ClassLoader), but is successfully loaded by AppClassloader, and according to the overall delegate rule, our Dog class is also loaded by AppClassLoader. So you must remember this crucial conclusion. Lay a solid foundation for our later study.

Let's look at another example. Let's delete the Person.class file under the classpath, and then run the main function above to see the result. The code is as follows:

From the results of that line, we can see that the Person class is loaded by our custom class loader. Then why the Dog class does not fully delegate? this is because of the parental delegate model, there is no Person class under our classpath, so AppClassLoader cannot load the com.test.Person.class file under our path I:\ test\. So the Person class is loaded by our custom class loader. If you look at the Dog class, because its loading follows the parent delegate model, and because there is a Dog.class file under the classpath, AppClassLoader can load the Dog class. So the ClassLoader that loads the Dog class is AppClassLoader. At this point, you have a very deep understanding of class loading. So I believe the benefits of java's use of the parental delegation model are self-evident. So let's talk about the parental entrustment model. Does it have any disadvantages, or is there anything bad about it? Can we break this parental delegate way to load classes? Let's look at an example.

The namespace of the class loader

When it comes to the disadvantages of the parental delegation model, I can't do without the concept of namespaces.

The namespace of the classloader consists of the classloader itself and all the binary name (full class name) loaded by the parent loader.

①: two identical binary name are not allowed in the same namespace.

②: two identical binary name can appear in different namespaces. Of course, the corresponding Class objects are imperceptible to each other, that is to say, the types of Class objects are different.

Explanation: if the same Person.class file is loaded by our different class loaders, two corresponding Person Class objects will be generated in our jvm memory, and the two corresponding Class objects are invisible to each other (instance objects created by Class object reflection are incompatible with each other and cannot be transformed into each other * *

③: the class corresponding to binary name in the namespace of the child loader can be accessed from the class corresponding to binary name in the namespace of the parent loader, and vice versa

Here is a picture for everyone to understand.

The above diagram explains the concept of namespaces very well. You can have a good experience again.

It is not a very strong evidence that we just draw pictures and say it with our mouths. As I mentioned when I wrote in this blog, when we learn and master a concept, we must come up with strong evidence to prove our conjecture or point of view. Let's give an example. To verify whether our above theory is correct. The code is as follows:

This is the code for the Person class.

Package com.test;public class Person {public Person () {new Dog (); System.out.println ("classLoader:-- of Dog >" + Dog.class.getClassLoader ());} static {System.out.println ("person class is initialized");}}

This is the code for the Dog class.

Package com.test;public class Dog {public Dog () {System.out.println ("constructor of Dog");}}

The specific verification idea is as follows: first, we put the Class file of the Person class into the loading directory of the boot class loader (C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ classes, which is the loading directory of the startup class loader) to achieve the purpose of loading the Person class to the startup class loader.

Then, we let the Dog class be loaded by the AppClassLoader (system class loader). Then we visit the Dog class in the Person class. See if the visit is successful.

Test environment: put our Person.class in C:\ Program Files\ Java\ jdk1.8.0_131\ jre\ classes, then our Person.class will be loaded by our startup class loader, our Dog class will be loaded by AppClassLoader, and our Dog class referenced in our Person class will throw an exception.

Create a main method to test:

Package com.test;import java.lang.reflect.Method;/** * jvm Class Loader Chapter 1 * @ author geek time-time * Custom Class Loader-Namespace * Test the classes loaded by the parent and cannot access the classes loaded by the child loader. * / public class MainClass02 {public static void main (String [] args) throws Exception {System.out.println ("Person classloader:" + Person.class.getClassLoader ()); System.out.println ("Dog classloader:" + Dog.class.getClassLoader ()); Class clazz = Person.class; clazz.newInstance () }} run result: "C:\ Program Files\ Java\ jdk1.8.0_144\ bin\ java.exe"-javaagent:C:\ Program Files\ JetBrains\ IntelliJ IDEA 2019.2\ lib\ idea_rt.jar=59226:C:\ Program Files\ JetBrains\ IntelliJ IDEA 2019.2\ bin "- Dfile.encoding=UTF-8-classpath" C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ charsets.jar C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ deploy.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ access-bridge-64.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ cldrdata.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ dnsns.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ jaccess.jar C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ jfxrt.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ localedata.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ nashorn.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ sunec.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ sunjce_provider.jar C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ sunmscapi.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ sunpkcs11.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ zipfs.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ javaws.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ jce.jar C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ jfr.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ jfxswt.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ jsse.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ management-agent.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ plugin.jar C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ resources.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ rt.jar I:\ jvm\ out\ production\ jvm-classloader "com.test.MainClass02Person classloader: nullDog classloader: sun.misc.Launcher$AppClassLoader@18b4aac2person class is initialized Exception in thread" main "java.lang.NoClassDefFoundError: com/test/Dog at com.test.Person. (Person.java:7) at sun.reflect.NativeConstructorAccessorImpl.newInstance0 (Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance (NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance (DelegatingConstructorAccessorImpl.java:45) at java. Lang.reflect.Constructor.newInstance (Constructor.java:423) at java.lang.Class.newInstance (Class.java:442) at com.test.MainClass02.main (MainClass02.java:20) Process finished with exit code 1

Summary: from the above code, we can see that when we went to new an instance of Dog in Person, we did not create it successfully, but threw an exception such as Exception in thread "main" java.lang.NoClassDefFoundError: com/test/Dog, which proves our conclusion (the class loaded by the parent loader cannot access the class loaded by the child. )

That is, the classes loaded by the startup class loader cannot access the classes loaded by the system class loader (AppClassLoader).

So someone is sure to ask, can the classes loaded by our child loader access the classes loaded by the parent loader? We might as well prove that we just need to change the code of the MainClass02 class, let AppClassLoader load the Dog class, and let our custom class loader load our Person class. And access the Dog class in the Person class. Then delete the Class file in the Person in the previous C:\ Program Files\ Java\ jdk1.8.0_131\ jre\ classes directory, delete the Person file under our classpath, and add the com.test.Person.class file in the I:\ test\ directory. The code is as follows:

Package com.test;import java.lang.reflect.Method;/** * jvm Class Loader Chapter 1 * @ author geek time-time * Custom Class Loader * Test whether the class loaded by the subclass loader can access the class loaded by the parent loader. * / public class MainClass02 {public static void main (String [] args) throws Exception {/ / create an instance of the custom classloader and specify the name Test01ClassLoader myClassLoader = new Test01ClassLoader ("loader1") through the constructor; myClassLoader.setPath ("I:\\ test\"); Class classz = myClassLoader.loadClass ("com.test.Person"); System.out.println (classz.getClassLoader ()) System.out.println ("Dog classloader:" + Dog.class.getClassLoader ()); classz.newInstance () }} run result: "C:\ Program Files\ Java\ jdk1.8.0_144\ bin\ java.exe"-javaagent:C:\ Program Files\ JetBrains\ IntelliJ IDEA 2019.2\ lib\ idea_rt.jar=60588:C:\ Program Files\ JetBrains\ IntelliJ IDEA 2019.2\ bin "- Dfile.encoding=UTF-8-classpath" C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ charsets.jar C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ deploy.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ access-bridge-64.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ cldrdata.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ dnsns.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ jaccess.jar C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ jfxrt.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ localedata.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ nashorn.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ sunec.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ sunjce_provider.jar C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ sunmscapi.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ sunpkcs11.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ ext\ zipfs.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ javaws.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ jce.jar C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ jfr.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ jfxswt.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ jsse.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ management-agent.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ plugin.jar C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ resources.jar;C:\ Program Files\ Java\ jdk1.8.0_144\ jre\ lib\ rt.jar;I:\ jvm\ out\ production\ jvm-classloader "com.test.MainClass02 's own class loader is loaded with com.test.Test01ClassLoader@677327b6Dog 's class loader: sun.misc.Launcher$AppClassLoader@18b4aac2Dog 's constructor Process finished with exit code 0

As you can see from the above results, Person is loaded by our Test01ClassLoader custom class loader, so its parent loader is AppClassLoader, and obviously the Dog class is loaded by our AppClassLoader. Therefore, the code runs normally and no exception is thrown, which leads to the conclusion:

1: the class loaded by the parent loader cannot access the class loaded by the child loader. 2: classes loaded by the child loader can access the classes loaded by the parent loader. The disadvantages of the parental entrustment model

Let's first look at a code snippet related to database connections that we are very familiar with.

Class.forName ("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection ("jdbc:mysql://localhost:3306/RUNOOB", "root", "123456"); Statement stmt = conn.createStatement ()

Case analysis

Why is the fifth step in the above figure loaded with a thread context loader?

Under the mechanism of the parent delegate model, the class is loaded from the bottom up. That is, the loader of the lower layer will delegate to the upper layer to load. Some interfaces are provided by the Java core library (rt.jar), such as the createStatement interface above, while the Java core library is loaded by the startup class loader. The specific implementation of these interfaces comes from different vendors (Mysql). The specific implementation is put under the classPath in our project by relying on the jar package. Java's startup class loader / root class loader does not load jar packages from these other sources.

We all know that the jar package under classPath is loaded by our system class loader / application loader. According to the mechanism entrusted by our parents, the parent class loader can not see the specific implementation loaded by the subclass (system class loader). The interface createStatement is loaded by the root class loader and the specific implementation cannot be loaded. Under the mechanism of parental delegation, there is no concrete implementation of the interface createStatement.

We Java developers can load the interface implementation class by setting the context loader to the current thread pool. In other words, the parent class loader can use the current thread context loader to load implementations of interfaces that the parent class loader cannot load. It perfectly solves the interface calls due to the SPI model (the interface is defined in the core library, and the implementation is dependent on our project by their respective vendors in the form of jar).

Below I provide a flow chart of SPI. If you don't know what SPI's friends are, you can take a look at this picture:

From the above example, we can see the disadvantages of the parental delegation model. Then our jdk provides us with a way to break this parental delegate by modifying thread context class loading. On the topic of modifying thread context class loading, we will explain it in detail in the next chapter. Next, let's take a look at several ways to get the classloader. And send you the translated java doc documents. It is convenient for us to follow up on the thread class loader.

Several methods of getting class loader

Class.getClassLoader ()

/ * Returns the class loader for the class (returns the class loader that loads the class). Some implementations may use* null to represent the bootstrap class loader (some implementations of jvm may use null to represent our boot class loader such as hotspot). * This method will return null in such implementations if this class was loaded by the bootstrap class loader.* if this method returns null, then this class is loaded by our boot class loader * * If this object represents a primitive type or void, null is returned. (primitive types such as classes of int,long, etc., or void type, then their class loader is null) * * / public ClassLoader getClassLoader () {ClassLoader cl = getClassLoader0 (); if (cl = = null) return null;SecurityManager sm = System.getSecurityManager (); if (sm! = null) {ClassLoader.checkClassLoaderPermission (cl, Reflection.getCallerClass ());} return cl;}

1: returns the classloader representing the loading of the class

2: the startup class loaders of some virtual machines (such as hotspot) are represented by null.

3: primitive types such as int, long or void, whose classloader is null

Interpretation of ClassLoader.getSystemClassLoader () method

/ * Returns the system class loader for delegation (this method returns the system class loader). This is the default* delegation parent for new ClassLoader instances (also the delegate parent of our own defined classloader), and is* typically the class loader used to start the application (usually the system classloader is used to launch our application) * * This method is first invoked early in the runtime's startup* sequence (the program calls this method early in the run), at which point it creates the system class loader and sets it* as the context class loader of the invoking Thread. (at that time, the calling thread creates our system class loader and sets the system class loader to our thread context) * *

The default system class loader is an implementation-dependent* instance of this class. (this sentence is not well understood) * *

If the system property "java.system.class.loader" is defined* when this method is first invoked then the value of that property is* taken to be the name of a class that will be returned as the system* class loader. The class is loaded using the default system class loader* and must define a public constructor that takes a single parameter of* type ClassLoader which is used as the delegation parent. An* instance is then created using this constructor with the default system* class loader as the parameter. The resulting class loader is defined* to be the system class loader. We can specify the binary name of a custom class load as the new system class loader through the java.system.class.loader system property. In our custom load, we need to define a constructor with parameters. If the parameter is classLoader, then our custom class loader will be regarded as the system class loader * * @ return The system ClassLoader for delegation Or* null if none** @ throws SecurityException* If a security manager exists and its checkPermission* method doesn't allow access to the system class loader.** @ throws IllegalStateException* If invoked recursively during the construction of the class* loader specified by the "java.system.class.loader" * property.** @ throws Error* If the system property "java.system.class.loader" * is defined but the named class could not be loaded, the* provider class does not define the required constructor, or an* exception is thrown by that constructor when it is invoked. The* underlying cause of the error can be retrieved via the* {@ link Throwable#getCause ()} method.** @ revised 1.4*/@CallerSensitivepublic static ClassLoader getSystemClassLoader () {/ / initialize the system class loader initSystemClassLoader (); if (scl = = null) {return null;} SecurityManager sm = System.getSecurityManager (); if (sm! = null) {checkClassLoaderPermission (scl, Reflection.getCallerClass ());} return scl;}

1: the purpose of this method is to return the system class loader

2: it is also the direct parent of our custom loader

3: the system class loader is used to start our application

4: in the early days of the system, the calling thread created our system class loader and set our system class loader to the context of the current thread.

5: we can specify our custom class loader to act as our system class loader through the system property: java.system.class.loader, but our custom loader needs to provide a constructor with parameters (classloader)

At this point, the study of "what is a class loader in the art of JVM" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

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