ClassLoader Mechanism

xiaoxiao2021-03-17  185

When the JVM (Java virtual machine) is started, the initial class loader hierarchy consisting of three type loaders is formed:

Bootstrap ClassLoader

|

Extension ClassLoader

|

System ClassLoader

Bootstrap ClassLoader - Boot (also known as the original) class loader, which is responsible for loading the core class of Java. In the JVM in Sun, use the -XbootclassPath option in the Java command or use the -d option to specify the additional class. This loader is very special. It is actually not subclass of Java.lang.classLoader, but is implemented by JVM itself. You can get the core class library by performing the following code to get the Bootstrap ClassLoader loading those core class libraries:

URL [] URLS = Sun.misc.launcher.getBootstrapClassPath (). GetURLS ();

For (int i = 0; i

System.out.println (Urls.ToExternalForm ());

}

The result on my computer is:

File: / c: /j2sdk1.4.1_01/jre/lib/endorsed/Dom.jar

File: / c: /j2sdk1.4.1_01/jre/lib/endorsed/sax.jar

File: / c: /j2sdk1.4.1_01/jre/lib/endorsed/xalan-2.3.1.jar

File: / c: /j2sdk1.4.1_01/jre/lib/endorsed/xercesimpl-2.0.0.jar

File: / c: /j2sdk1.4.1_01/jre/lib/endorsed/xml-apis.jar

File: / c: /j2sdk1.4.1_01/jre/lib/endorsed/xsltc.jar

File: / c: /j2sdk1.4.1_01/jre/lib/rt.jar

File: / c: /j2sdk1.4.1_01/jre/lib/i18n.jar

File: / c: /j2sdk1.4.1_01/jre/lib/sunrsasign.jar

File: / c: /j2sdk1.4.1_01/jre/lib/jsse.jar

File: / c: /j2sdk1.4.1_01/jre/lib/jce.jar

File: / c: /j2sdk1.4.1_01/jre/lib/charsets.jar

File: / c: /j2sdk1.4.1_01/jRE/Classes

At this time, everyone knows why we don't need to specify these class libraries in the system properties ClassPath, because JVM is automatically loaded when starting.

Extension ClassLoader - Extended class loader, which is responsible for loading JRE's extended directory (Java_Home / JRE / LIB / EXT or by java.ext.dirs system properties) JAR's class package. This provides a standard mechanism for introducing new features other than Java core classes. Because the default extension directory is common to all JVMs that start from the same JRE, the JAR class packages that are placed in this directory are visible to all JVMs and System ClassLoader. Calling method getparent () always returns null null because the bootloader Bootstrap ClassLoader is not a real ClassLoader instance. So when you do the following code:

System.out.println (System.GetProperty))))); "Java.ext.dirs");

ClassLoader ExtensionClassLoader = ClassLoader.getsystemClassLoader (). GetParent (); System.out.println ("The Parent of ExtensionLoader: ExtensionClassLoader.getParent ());

The result is:

C: /J2SDK1.4.1_01/jre/lib/ext

The Parent of Extension ClassLoader: Null

Extension ClassLoader is the Parent of System ClassLoad, while bootstrap classloader is the Parent of Extension ClassLoader, but it is not an actual ClassLoader, so for null.

System ClassLoader - System (also known as application) class loader, which is responsible for loading the -classpath or java.class.path system attribute or ClassPath operating system properties in JVM, or the JAR class package specified by the ClassPath operating system properties at the JVM startup And class paths. This type of loader can always be found by static method classloader.getsystemClassLoader (). If there is no special specification, the user-defined any class loader uses the class loader as its parent loader. You can get the following code:

System.out.println (System.GetProperty ("java.class.path");

The output result is the classpath set in the system properties in the system properties.

The ClassLoader loaded is used by the whole district. The so-called whole is responsible, that is, when a ClassLoader loads a class, all Class depends on and references all CLASSs are responsible for loading, unless explicitly uses another ClassLoader load; the principal mechanism is first Let the Parent (Father) class loader (instead of super, it is not inherited with the Parent ClassLoader class), only in your own classpaths when you can't find it. In addition, the Cache mechanism is also used, that is, if the Cache saves this class directly, if you don't read and convert it from the file, it is stored in cache, which is why we modified Class but must Refact the reason for the JVM to take effect.

The process of loading the Class of the ClassLoader is:

1. Check if this Class is loaded (ie there is this class in cache), if there is an 8, if there is no 2

2. If the Parent ClassLoader does not exist (no perent, the parent must be bootstrap classloader), to 4

3. Request Parent ClassLoader load, if successful to 8, unsuccessful to 5

4. Request JVM from Bootstrap ClassLoader, if successful to 8

5. Look for class files (from being found from the classpath associated with this ClassLoader). If you can't find it, it is 7.

6. Load Class from the file to 8.

7. Throw ClassNotFoundException.

8. Return to Class.

Of these 5.6 steps we can implement your own load policy by overlying the ClassLoader's FindClass method. Even override the loadClass method to implement its own load process.

The order of the type loader is:

First Bootstrap ClassLoader, then the Extension ClassLoader, and finally System ClassLoader. Everyone will find that the loaded Class is more important, the more it is in front. The reason is for security considerations. Imagine if the System ClassLoader "personally" loads a consequence of a destructive "java.lang.system" class. This entrustment mechanism guarantees that even if the user has such a class, it also adds it to the class path, but it will never be loaded because this class is always loaded by Bootstrap ClassLoader. You can perform the following code: System.out.println (System.class.getClassLoader ());

The result will be seen is Null, which indicates that java.lang.system is loaded by Bootstrap ClassLoader because Bootstrap ClassLoader is not a real ClassLoader instance, but is implemented by JVM, as already said earlier.

Let's take a look at how the JVM is to build the structure of the class loader:

Sun.misc.launcher, as the name suggests, when you execute the java command, JVM will use the bootstrap classloader to load and initialize a Launcher, execute the code:

System.Out.Println ("The Launcher's ClassLoader IS" Sun.misc.launcher.getlauncher (). GetClassLoader ());

The result is:

The launcher's classloader is null (Because it is loaded with Bootstrap ClassLoader, Class Loader is NULL)

Launcher will initialize the Class Loader structure according to the system and command, and the JVM uses it to get Extension ClassLoader and System ClassLoader, and load all the Class to load, and finally execute the Java command with static main method. Class. EXTENSION CLASSLOADER is actually an instance of the Sun.Misc.launcher $ ExtClassLoader class, and System ClassLoader is actually an instance of Sun.Misc.Launcher $ AppClassLoader class. And all subclasses of java.net.urlclassloader.

Let's take a look at some of the code of the Launcher's initial test process.

Part of Launcher's code:

Public class launcher {

Public launcher () {

EXTCLASSLOADER EXTCLASSLOADER;

Try {

// Initialize Extension ClassLoader

EXTCLASSLOADER = EXTCLASSLOADER.GETEXTCLASSLOADER ();

} catch (ioexception ioException) {

Throw New INTERNALROR ("COULD NOT CREATE EXTENSION CLASS Loader");

}

Try {

// Initialize System ClassLoader, Parent is Extension ClassLoader

Loader = AppClassLoader.GetAppClassLoader (EXTCLASSLOADER);

} catch (ioException ioException1) {

Throw new interfacerror ("Could Not Create Application Class Loader);

// Set the system classloader to the current ClassLoader of the current thread (will be introduced later)

Thread.currentthread (). SetContextClassLoader (Loader);

......

}

Public classloader getClassLoader () {

/ / Return to System ClassLoader

Return loader;

}

}

Part of the EXTENSION CLASSLOADER:

Static Class Launcher $ EXTCLASSLOADER EXTENDS URLCLASSLOADER {

Public Static Launcher $ EXTCLASSLOADER getExtClassLoader ()

Throws oException

{

File Afile [] = getextdirs ();

Return (Launcher $ ExtclassLoader AccessController.doprivileged (New Launcher $ 1 (Afile);

}

Private static file [] getExtDirs () {

// Get system properties "java.ext.dirs"

String s = system.getProperty ("java.ext.dirs");

File Afile [];

IF (s! = null) {

StringTokenizer StringTokenizer = New StringTokenizer (S, File.PathseParetor);

INT i = StringTokenizer.countToKens ();

Afile = new file;

For (int J = 0; j

Afile [J] = New file (StringTokenizer.nextToken ());

} else {

Afile = new file [0];

}

Return Afile;

}

}

Some code of System ClassLoader:

Static Class Launcher $ AppClassLoader Extends UrlclassLoader

{

Public Static ClassLoader GetAppClassLoader (ClassLoader ClassLoader)

Throws oException

{

// Get system properties "java.class.path"

String s = system.getProperty ("java.class.path");

File Afile [] = s! = Null? Launcher.access $ 200 (s): New file [0];

Return (Launcher $ AppClassLoader) AccessController.doprivileged (New Launcher $ 2 (S, Afile, ClassLoader);

}

}

If you read the source code, you will clear it, and Extension ClassLoader is using the system properties "java.ext.dirs" to set the class search path, and there is no Parent. System ClassLoader is the use of system properties "java.class.path" setting class search path, and has a Parent ClassLoader. Launcher Initialize Extension ClassLoader, System ClassLoader, and sets the System ClassLoader to Context ClassLoader, but only returns System ClassLoader to JVM. How come here again a Context ClassLoader? What is it used? When we create a thread thread, we can specify a suitable classLoader as this thread's Context ClassLoader for this thread. When this thread runs, we can use the GetContextClassLoader method to get this Context ClassLoader. You can use It loads the Class we need. The default is System ClassLoader. With this feature, we can "break" ClassLoader entrustment mechanism, the parent ClassLoader can get the current ClassLoader of the current thread, and this Context ClassLoader can be its sub-ClassLoader or other ClassLoader, then the parent ClassLoader can get the required Class, this breaks the restrictions that can only be requested to the parent ClassLoader. This mechanism can meet when our ClassPath is determined at runtime, and when the custom ClassLoader is loaded, the class loaded by System ClassLoader (ie, in JVM ClassPath) can get custom ClassLoader to get custom ClassLoader through the Context ClassLoader and load specific Class (usually abstract classes and interfaces, customized ClassLoad is achieved), such as servlets in web applications are loaded with this mechanism.

Ok, now we understand the structural and working principle of ClassLoader, then how do we achieve dynamic load and updates during runtime? As long as we can dynamically change the class search path and clear the Class that has been loaded in ClassLoader, there are two options. One is very simple and practical, just re-use a new class search path to New a classloader, so that you update the class search path to load a new Class, and regenerate a blank cache (of course, class search The path does not necessarily change). Oh, great, we have hard work, Java.NeturlclassLoader is a ClassLoader that meets our requirements! We can use it directly or inherit it!

This is a description of the two constructor of the UrlclassLoader in the J2SE1.4 API:

UrlclassLoader (URL [] URLS)

CONSTRUCTS A NEW URLCLASSLOADER for The Specified Urls Using The Default Delegation Parent ClassLoader.

UrlclassLoader (URL [] URLS, ClassLoader Parent)

Constructs a new urlclassloader for the given Urls. Where the URL [] URLS is the class search path we have to set, and Parent is this ClassLoader's Parent ClassLoader, the default is System ClassLoader.

Ok, now we can dynamically load Class, so we can use the NewInstance method to get an object. But how do we use this Object shape? Can this Object create a Class itself?

Let us first analyze the compilation of the Java source file! The Javac command is compiled by "com.sun.tools.javac.main" in "java_home / lib / Tools.jar" to compile:

Public static int compile (String as []);

Public Static Int Compile (String as [], PrintWriter PrintWriter;

Returns 0 indicates that the compilation is successful, and the string array AS is the parameters we compile with the javac command, and divided by space. E.g:

Javac-ClassPath C: /FOO/Bar.jar ;. -d C: / C: /some.java

The string array AS is {"-classpath", "c: //foo//bar.jar ;.", "-d", "c: //", "c: //some.java"}, If you have a PrintWriter parameter, you will be able to go to this specified PrintWriter. The default output is System.err.

Where main is loaded by JVM using Launcher initialized System ClassLoader, according to the principle of the entire disc, the compiler will be loaded and referenced by the compiler when it is resolved this Java source file, will be loaded by System ClassLoader if System ClassLoader When you can't load a Class, the compiler will throw a "Cannot Resolve Symbol" error.

So first compile, it is not, that is, the compiler cannot compile a Java source file that references unknown Class in ClassPath, and because of spelling errors or not put the required class library into classpath, everyone must often see this " CANNOT Resolve Symbol "This compilation error!

Second, let's put this class in the compilation path, successfully compiled, and then put it in the ClassPath when running, use our own classloader to dynamically load this class, this will also appear "Java.lang.noclassdeffounderror" violation, why?

Let's analyze it, first call this stylist's executable Class, must be loaded by the JVM initialized System ClassLoader, according to the principle of the whole, when we make shape, JVM will also use System ClassLoader to try Enter this class to make an instance, naturally throw a violation of "java.lang.noclassdeffounderror" when you find this ClassLoader without this class.

OK, now let us summarize the compilation of the Java file and the load execution of the Class, which is used using Launcher initialized System ClassLoader as a class loader. We can't change the System ClassLoader, you can't let JVM use us themselves. ClassLoader replaces SYSTEM CLASSLOADER, according to the principle of the whole, limits compilation and running, we can't directly explicitly use a System ClassLoader to find ClassLo, that is, we can only use the Java core library, extended class libraries and Class in class library in ClassPath. Still don't die! Try this again, we put this Class into the ClassPath and let System ClassLoader recognize and load. Then we load this class from the specified ClassLoader (cannot be entrusted to load, because this will be loaded from the ClassPath from the classpath, and then instantiate an ObjectLoad, and model it into this Class, so JVM also recognizes this class (because System ClassLoader is able to locate and load this class from ClassPath), loaded nor the ClassPath this class, but from the ClassPath external dynamic, so that the head is! Unfortunately, "java.lang.classcastexception" violation will appear.

why? We also have to analyze, good, though we use our own ClassLoader dynamics from ClassPath, but when it is molded, the JVM will use System ClassLoad to load this Class, and try to use One instance of our own ClassLoader loaded Class is the Class (additional) that is loaded with System ClassLoader. Did you find any questions? That is, we try to use an instance of Class Load from a ClassLoader to another ClassLoader loaded Class, although the names of these two Class are loaded from the same class file. But unfortunately, JVM thinks that this two class Class is different, that is, JVM thinks the same name of the same name of different classloader (even if it is loaded from the same class file) is different! The reason I think. I think it is also mainly for security considerations, so that all core Java classes are loaded by System ClassLoader, we cannot replace them with instances of the same name of the same name loaded with their own ClassLoader. Example.

Seeing this, a smart reader must think of how to dynamically load our class, instantiate, shape and call it!

That is to use the versatility of one of the object-oriented basic characteristics. We use the example of our dynamic load Class to make a parent class that it can identify by it! Why is this? We still have to analyze it again. When we use our own ClassLoader to dynamically load this, we will find it with a parent class, which will load this parent class, which will load this parent class, which will load this parent class, which will load this parent classLASS. It can be identified, depending on the principal mechanism, it will be loaded by System ClassLoader, then our ClassLoader loads this class, create an instance, styling this parent class Class, pay attention, styling into this parent class class (also It is traceable) to be an object-oriented Java language allowed and JVM also supported, JVM uses System ClassLoad to load this parent class Class again, and then make this instance to this parent class Class. Everyone can find that this parent class Class is loaded by System ClassLoad, which is the same class of Class Loader, so there will be no exceptions when the shape is styled. According to the multi-shaped method, when the method of calling this parent class is truly executed, this Class (non-parent class class) overwrites the method of the parent method. These methods can also be used to reference the classLlassLoader ClassLoader, because according to the principle of the whole, as long as the ClassLoader loaded into this ClassLoad, the ClassLoader we define can be positioned and loaded into these classes. This way we can define a set of interfaces or base classes in advance and put them in ClassPath, and then dynamically load the subclass of these interfaces or base classes when executed. Don't you understand? Let's think about servlet, Web Application Server can load any Class inherited servlet and perform them correctly, no matter what it actually class is, all instantiate them into a servlet class, then execute servlet Init, dopost, doget, and Destroy, etc., regardless of this servlet is dynamically loaded from Sub-INF / LIB and Web-INF / CLASSES by System ClassLoader sub-ClassLoader (ie, custom ClassLoader). Said that so many hopes, everyone will understand. This mechanism is used in containers such as applet, EJB.

For the above circumstances, I hope that everyone can actually write some Example to experiment.

Finally, I said something else, although ClassLoader is called a class loader, but does not mean only to load CLASS, we can also use it to get the URL of resources such as pictures, audio files, of course, these resources must be in ClassPath. In the JAR class library or in the directory. Let's take a look at the two ways to find resources and Class of ClassLoader in the API DOC:

Public url getresource (String name)

Using the specified name to find resources, one resource is some data that can be accessed by the Class code (picture, audio, text, etc.) that depend on the code location to be accessed by the Class code.

The name of a resource is the path name that determines the resource with the '/' number.

This method will first request a Parent ClassLoad to search for resources. If there is no Parent, you will search in the path to the ClassLoader (ie, Bootstrap ClassLoader) built in the virtual machine. If you fail, this method will call FindResource (String) to find resources. Public static url getSystemResource (String name)

Find a resource that specifies the name from the search path used to load the class. This method uses System Class Loader to locate resources. That is, it is equivalent to classloader.getsystemClassLoader (). Getresource (name).

E.g:

System.out.println (ClassLoader.getsystemResource ("Java / Lang / String.class)));

The result is:

Jar: file: / c: /j2sdk1.4.1_01/jre/lib/rt.jar! /java/lang/string.class

Indicates that string.class files in the Java / LANG directory of RT.jar.

So we can pack pictures and other resources to pack them into the JAR class library with Class (of course, you can also package these resources separately) and add them to the Class Loader search path, we can do not need to care about these resources, let Class Loader is looking for us!

转载请注明原文地址:https://www.9cbs.com/read-129511.html

New Post(0)