Java classloader Dynamic Loading

Source: Internet
Author: User

Http://smallbee.iteye.com/blog/638393

When the JVM (Java Virtual Machine) is started, an initial class loader hierarchy consisting of three class loaders is formed:

Bootstrap classloader
|
Extension classloader
|
System classloader

Bootstrap classloader-the bootstrap (also called the original) Class Loader, which loads the Java core class. In Sun's JVM, you can use the-xbootclasspath option or the-D option to specify the sun. boot. Class. Path System attribute value to specify the additional class in the Java command. This loader is very special. It is not actually a subclass of Java. Lang. classloader, but implemented by JVM itself. You can run the following code to obtain the core class libraries loaded by bootstrap classloader:
URL [] URLs = sun. Misc. launcher. getbootstrapclasspath (). geturls ();
For (INT I = 0; I <URLs. length; I ++ ){
System. Out. println (URLs [I]. 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/export TC. 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
Now we know why we don't need to specify these class libraries in the system attribute classpath, because the JVM automatically loads them at startup.

Extension classloader-extension class loader, which is responsible for loading the extension directory of JRE (java_home/JRE/lib/EXT or by Java. ext. jar class package specified by the dirs system attribute. This provides a standard mechanism for introducing new features other than the Java core class. Because the default extension directory is common to all JVM started from the same JRE, the jar class package that is placed in this directory is visible to all JVM and system classloader. The call method getparent () on this instance always returns a null value, because Bootstrap classloader is not a real classloader instance. So when you execute the following code:
System. Out. println (system. getproperty ("Java. Ext. dirs "));
Classloader extensionclassloader = classloader. getsystemclassloader (). getparent ();
System. Out. println ("the parent of extension classloader:" + extensionclassloader. getparent ());
Result:
C:/j2sdk1.4.1 _ 01/JRE/lib/EXT
The parent of extension classloader: NULL
Extension classloader is the parent of system classloader, while Bootstrap classloader is the parent of extension classloader, but it is not an actual classloader, so it is null.

System classloader-the system (also called an application) Class Loader is responsible for loading-classpath or Java from the Java command when the JVM is started. class. the jar package and path specified by the path system attribute or the classpath operating system attribute. You can always find the Class Loader through the static classloader. getsystemclassloader () method. If this parameter is not specified, the user-defined class loader uses the class loader as its parent loader. Run the following code:
System. Out. println (system. getproperty ("Java. Class. Path "));
The output result is the classpath set in the system attributes.
Classloader is used to load classes and is fully responsible for delegation. The so-called full responsibility means that when a classloader loads a class, the classloader is responsible for loading all the classes that this class depends on and references, unless it is explicitly loaded using another classloader, the delegate mechanism is to first look for the parent (parent) Class Loader (instead of super, it is not an inheritance relationship with the parent classloader class, you can only search for it from your own class path when the parent cannot be found. In addition, the cache mechanism is used for class loading, that is, if the class is saved in the cache, it is directly returned. If the class is not saved, it is read from the file and converted to the class, and saved to the cache, this is why we modified the class but had to restart JVM to take effect.

The process for each classloader to load a class is as follows:
1. check whether this class has been loaded (that is, whether this class exists in the cache). If there is 8, if not
2. If the parent classloader does not exist (there is no parent, the parent must be the bootstrap classloader ),
3. Request the parent classloader for loading. If it succeeds to 8, it fails to reach 5.
4. Request JVM to load from Bootstrap classloader.
5. Search for the class file (from the class path related to this classloader ). If not found, it will be 7.
6. Load the class from the file to 8.
7. Throw classnotfoundexception.
8. Return class.

In step 1, we can implement our own loading policy by overwriting the findclass method of classloader. It even overwrites the loadclass method to implement its own loading process.

The sequence of class loaders is:
Bootstrap classloader, extension classloader, and system classloader. You will find that the more important the loaded class is, the more important it is. This is because of security considerations. Imagine the consequence of loading a destructive "Java. Lang. System" class by system classloader. This delegate mechanism ensures that even if you have such a class, you can add it to the class path, but it will never be loaded, because this class is always loaded by bootstrap classloader. You can execute the following code:
System. Out. println (system. Class. getclassloader ());
The result is null, which indicates that Java. lang. system is loaded by bootstrap classloader, because Bootstrap classloader is not a real classloader instance, but implemented by JVM, as mentioned earlier.

Next let's take a look at how JVM creates the Class Loader structure for us:
Sun. Misc. launcher, as the name suggests, When you execute a Java command, JVM will first use Bootstrap classloader to load and initialize a launcher and execute the Code:
System. Out. println ("the launcher's classloader is" + sun. Misc. launcher. getlauncher (). getclass (). getclassloader ());
Result:
The launcher's classloader is null (because it is loaded with bootstrap classloader, so class loader is null)
Launcher initializes the Class Loader structure according to the system and command settings, and JVM uses it to obtain extension classloader and system classloader, and load all the classes to be loaded, finally, execute the class specified by the Java command with the static main method. Extension classloader is actually an instance of the sun. Misc. launcher $ extclassloader class. The system classloader is actually an instance of the sun. Misc. launcher $ appclassloader class. And they are all subclasses of java.net. urlclassloader.

Let's take a look at some of the Code in the initial testing process of launcher.

Part of the launcher code:
Public class launcher {
Public launcher (){
Extclassloader;
Try {
// Initialize extension classloader
Extclassloader = extclassloader. getextclassloader ();
} Catch (ioexception ){
Throw new internalerror ("cocould not create extension class loader ");
}
Try {
// Initialize the system classloader. The parent is the extension classloader.
Loader = appclassloader. getappclassloader (extclassloader );
} Catch (ioexception ioexception1 ){
Throw new internalerror ("cocould not create application Class Loader ");
}
// Set the system classloader to the context classloader of the current thread (which will be described later)
Thread. currentthread (). setcontextclassloader (loader );
......
}
Public classloader getclassloader (){
// Return system classloader
Return loader;
}
}

Some code of extension classloader:
Static class launcher $ extclassloader extends urlclassloader {

Public static launcher $ extclassloader getextclassloader ()
Throws ioexception
{
File afile [] = getextdirs ();
Return (launcher $ extclassloader) accesscontroller. doprivileged (new launcher $1 (afile ));
}
Private Static file [] getextdirs (){
// Obtain the system property "Java. Ext. dirs"
String S = system. getproperty ("Java. Ext. dirs ");
File afile [];
If (s! = NULL ){
Stringtokenizer = new stringtokenizer (S, file. pathseparator );
Int I = stringtokenizer. counttokens ();
Afile = new file [I];
For (Int J = 0; j <I; 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)
Throws ioexception
{
// Obtain the system attribute "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 ));
}
}

After reading the source code, you can see that extension classloader uses the system attribute "Java. Ext. dirs" to set the Class search path, and there is no parent. System classloader uses the system attribute "Java. Class. Path" to set the Class search path, and has a parent classloader. Launcher initializes extension classloader and system classloader, and sets system classloader as context classloader, but only returns system classloader to JVM.

How can we create another context classloader? What is its use? When we create a thread, we can use the setcontextclassloader method to specify a suitable classloader as the context classloader of the thread. When this thread is running, we can use the getcontextclassloader method to obtain the context classloader and use it to load the class we need. The default value is system classloader. With this feature, we can "break" The classloader delegation mechanism. The parent classloader can obtain the context classloader of the current thread, and the context classloader can be its sub-classloader or other classloader, then, the parent classloader can obtain the required class from it, which breaks the restrictions that can only be requested from the parent classloader. This mechanism can meet the requirements of system classloader (that is, in JVM classpath) when our classpath is determined at runtime and loaded by the custom classloader) you can use the context classloader to obtain the custom classloader and load it into a specific class (usually abstract classes and interfaces, which are implemented in the Custom classloader ), for example, servlets in web applications are loaded using this mechanism.

Now that we understand the structure and working principle of classloader, how can we achieve dynamic loading and updating at runtime? As long as we can dynamically change the Class search path and clear the loaded class in the classloader cache, there are two solutions. One is that we inherit a classloader and override the loadclass method, dynamically search for class files and use the defineclass method. The other method is very simple and practical. You only need to re-use a new class search path to create a new classloader, in this way, the Class search path is updated to load the new class and a blank cache is generated again (of course, the Class search path may not have to be changed ). Oh, good. We almost don't need to do anything. java. neturlclassloader is a classloader that meets our requirements! We can directly use or inherit it!

This is the description of the two constructors of urlclassloader in the j2se1.4 api doc:
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.
URL [] URLs is the class search path we want to set, and parent is the parent classloader of the classloader. The default value is system classloader.

Well, now we can dynamically load the class, so that we can use the newinstance method to get an object. But how can we shape this object? Can this object be modeled as its own class?

First, let's analyze the Java source file compilation and run it! The javac command is compiled by calling the compile method of "com. Sun. Tools. javac. Main" in "java_home/lib/tools. Jar:

Public static int compile (string as []);

Public static int compile (string as [], printwriter );

If the return value is 0, the compilation is successful, and the string array as is the parameter we used to compile with the javac command, which is divided by spaces. For example:
Javac-classpath C:/Foo/bar. jar;.-d c:/Some. Java
The string array as is {"-classpath", "C: // Foo // bar. jar ;. ","-d "," C: // "," C: // some. java "}. If the printwriter parameter is included, the compilation information is output to the specified printwriter. The default output is system. Err.

Main is loaded by the system classloader initialized by the JVM using launcher. According to the principle of full responsibility, when the compiler parses this Java source file, all the classes it depends on and references will also be loaded by the system classloader. If the system classloader cannot load a class, the compiler will throw a "cannot resolve symbol" error.

Therefore, the compiler cannot compile a Java source file that references an unknown class that is not in the classpath. The required class library is not put into the classpath due to spelling errors, you will often see this "cannot resolve symbol" compilation error!

Second, we put this class in the compilation path and compiled it successfully, then, we use our own classloader to dynamically load this class without putting it into classpath during running. At this time, "Java. lang. noclassdeffounderror "violation, why?

Let's analyze it again. the executable class that calls this styling statement must be loaded by the system classloader initialized by the JVM using launcher. According to the principle of full responsibility, when we perform styling, JVM will also use system classloader to try to load this class to shape the instance. Naturally, when the system classloader cannot find this class, it will throw "Java. lang. noclassdeffounderror.

OK. Now let's take a look at the summary. The compilation of java files and the loading and execution of class use the system classloader initialized by launcher as the class loader. We cannot dynamically change the system classloader, the JVM cannot replace the system classloader with our own classloader. According to the principle of full responsibility, compilation and runtime are restricted, we cannot directly use a class that the system classloader cannot find. That is, we can only use the Java core class library to extend the class library and the class in the class library in the classpath.

Not dead! Let's try again. We also put this class into classpath so that the system classloader can recognize and load it. Then we use our classloader to load this class from the specified class file (we cannot delegate parent loading, because it will be loaded by system classloader from classpath ), then instantiate an object and shape it into this class. In this way, JVM also recognizes this class (because the system classloader can locate and load this class from classpath ), this class is not loaded in the classpath, but is dynamically loaded outside the classpath. This is the general line! Unfortunately, the "Java. Lang. classcastexception" violation occurs.

Why? Let's also analyze it. Good, although we dynamically loaded this class using our own classloader from outside the classpath, however, when styling its instances, the JVM will use the system classloader to load the class again, and try to shape an instance of the class loaded using our own classloader as the class loaded by the system classloader (another one ). Have you found any problems? That is, we try to shape an instance of the class loaded from one classloader into another class loaded by another classloader. Although the names of the two classes are the same, it is even loaded from the same class file. Unfortunately, the JVM thinks that the two classes are different, that is, the JVM thinks that different classloader loads the Same Name class (even if it is loaded from the same class file) is different! The reason for doing so is probably mainly for security considerations, so that all core Java classes are System

When classloader is loaded, we cannot replace the instances of class with the same name loaded by our classloader.

Here, the smart readers must have thought about how to dynamically load, instantiate, shape, and call our class!

That is to take advantage of the polymorphism of one of the basic characteristics of object-oriented. We can shape the instance of the class we dynamically load into a parent class that the system classloader can recognize! Why? We still need to analyze it again. When we use our own classloader to dynamically load this class, we only need to find that it has a parent class. Before loading it, JVM will first load this parent class, this parent class can be identified by the system classloader. According to the delegate mechanism, it will be loaded by the system classloader, and then our classloader will load the class and create an instance, it is modeled as this parent class. Note that when it is modeled as this parent class (that is, the upstream class), it is allowed by the Object-Oriented Java language and supported by JVM, JVM uses system classloader to load the parent class again, and then shapes the instance as the parent class. From this process, we can find that the parent class is loaded by the system classloader, that is, the same class loaded by the same class loader. Therefore, no exception occurs during modeling. According to the polymorphism, when the method of the parent class is called, the actual execution of this class (non-parent class) overwrites the method of the parent class method. These methods can also reference the class that the system classloader cannot recognize, because according to the principle of full responsibility, as long as the classloader of this class is loaded, we can define the classloader to locate and load these classes.

In this way, we can define a group of interfaces or base classes in advance and put them into classpath. Then, we can dynamically load the implementation or inherit the subclass of these interfaces or base classes during execution. Don't you understand? Let's think about servlet. The Web application server can load any class that inherits the servlet and correctly execute them, no matter what the actual class is, all of them are instantiated into a servlet class, and then the servlet init, dopost, doget, destroy and other methods are executed, regardless of whether the servlet is dynamically loaded from the system classloader sub-classloader (custom classloader) under the web-INF/lib and web-INF/classes. I hope everyone can understand this. This mechanism is used in containers such as Applet and EJB.

For the above situations, I hope you can compile some examples for your experiment.

Finally, let me talk about other things. Although classloader is called a class loader, it does not mean that it can only be used to load classes. We can also use it to get URLs of images, audio files, and other resources. Of course, these resources must be in the jar class library or directory in classpath. Let's take a look at the two methods of searching for resources and classes in the api doc:
Public URL getresource (string name)
Use a specified name to search for resources. A resource is data (images, audios, texts, etc.) that can be accessed by class code depends on the code location to some extent ).
The name of a resource is separated by '/' to determine the path name of the resource.
This method will first request the parent classloader to search for resources. If there is no parent, it will be searched in the classloader (that is, bootstrap classloader) path built in the virtual machine. If this method fails, findresource (string) is called to search for resources.
Public static URL getsystemresource (string name)
Search for a resource with the specified 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 ).

For example:
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 the string. Class file is in the Java/lang directory of RT. jar.
Therefore, we can package images and other resources together with the class into the jar class library (of course, we can also package these resources separately) and add them to the search path of the class loader, we don't need to worry about the specific location of these resources, so let Class Loader help us find it!

After talking about this, I hope you can understand the loading mechanism and rules of Java classloader, and hope it will be helpful for future development. ^_^

Some information about Class Loader:

Http://dev.csdn.net/article/60/60806.shtm

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.