Java ClassLoader Principle Detailed Tutorial

Source: Internet
Author: User
Tags first row tomcat

One, what is ClassLoader?

As you know, when we write a Java program, it's not a CS or BS application, is a complete Java application organized by a number of. class files, when the program is running, it calls an entry function of the program to invoke the related functions of the system, which are encapsulated in different class files, so it is often necessary to invoke the class file from the other class file. method, if another file does not exist, a system exception is thrown. When the program starts, it does not load all the class files used by the program at once, but according to the needs of the program, the Java class loading mechanism (ClassLoader) dynamically loads a class file into memory, thus only the class file is loaded into memory To be referenced by another class. So ClassLoader is used to dynamically load class files into memory.

Two, Java defaults to provide three ClassLoader

    BootStrap ClassLoader: called the Startup class loader, Java class loading hierarchy is the topmost class loader, is responsible for loading the JDK core class library, such as: Rt.jar, Resources.jar, Charsets.jar, etc., you can obtain from the following program where the ClassLoader loaded the relevant jar or class file:

The code is as follows Copy Code
url[] url = Sun.misc.Launcher.getBootstrapClassPath (). Geturls ();
for (int i = 0; i < urls.length; i++) {
System.out.println (Urls[i].toexternalform ());
}



The following are the results obtained by the above program from the native JDK environment:
File:/c:/program%20files/java/jdk1.6.0_22/jre/lib/resources.jar
File:/c:/program%20files/java/jdk1.6.0_22/jre/lib/rt.jar
File:/c:/program%20files/java/jdk1.6.0_22/jre/lib/sunrsasign.jar
File:/c:/program%20files/java/jdk1.6.0_22/jre/lib/jsse.jar
File:/c:/program%20files/java/jdk1.6.0_22/jre/lib/jce.jar
File:/c:/program%20files/java/jdk1.6.0_22/jre/lib/charsets.jar
file:/c:/program%20files/java/jdk1.6.0_22/jre/classes/
In fact, the above results are also found by looking at the system properties of Sun.boot.class.path.

System.out.println (System.getproperty ("Sun.boot.class.path"));

Print Result: C:\Program Files\java\jdk1.6.0_22\jre\lib\resources.jar; C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar; C:\Program Files\java\jdk1.6.0_22\jre\lib\sunrsasign.jar; C:\Program Files\java\jdk1.6.0_22\jre\lib\jsse.jar; C:\Program Files\java\jdk1.6.0_22\jre\lib\jce.jar; C:\Program Files\java\jdk1.6.0_22\jre\lib\charsets.jar; C:\Program files\java\jdk1.6.0_22\jre\classes
Extension ClassLoader: called the Extended class loader, is responsible for loading Java extension class libraries, by default loading all jars under java_home/jre/lib/ext/.
App ClassLoader: called the System class loader, is responsible for loading all the jar and class files in the application Classpath directory.

Note: In addition to the three ClassLoader that Java defaults provide, users can also define their own classloader as needed, These custom classloader must inherit from the Java.lang.ClassLoader class, as well as the other two classloader provided by Java (Extension ClassLoader and app ClassLoader), but Bootstrap ClassLoader does not inherit from ClassLoader, because it is not an ordinary Java class, the bottom is written by C + +, has been embedded in the JVM kernel, when the JVM started, Bootstrap ClassLoader also starts with loading the core class library and constructs the extension ClassLoader and app ClassLoader ClassLoader.

The principle of ClassLoader loading class

1. Principle Introduction

ClassLoader uses a parental delegation model to search for classes, each ClassLoader instance has a reference to the parent class loader (not an inherited relationship, a contained relationship), and a built-in classloader for the virtual machine (Bootstrap ClassLoader) itself does not have a parent class loader, but can be used as a parent class loader for other ClassLoader instances. When a ClassLoader instance needs to load a class, it tries to delegate the task to its parent class loader, which is checked from top to bottom, first by the topmost class loader bootstrap ClassLoader attempting to load it. If it is not loaded, the task is forwarded to extension ClassLoader to attempt to load, if not loaded, to the app ClassLoader for loading, if it is not loaded, then return to the initiator of the delegate, It loads the class from a URL such as a specified file system or network. If none of them are loaded into this class, the ClassNotFoundException exception is thrown. Otherwise, the found class is generated with the definition of a class, loaded into memory, and finally returns the class instance object in memory.

2. Why use parents to entrust this model?

Because this avoids repeated loading, when the father has loaded the class, there is no need to classloader the load again. For security reasons, let's imagine that if we don't use this delegate pattern, we can use a custom string to dynamically override the types defined in the Java Core API, so there's a very large security risk, and the way the parents delegate can avoid that, Because string is already loaded at startup by the Boot class loader (BOOTSTRCP ClassLoader), the user-defined ClassLoader can never load a string that is written by itself. Unless you change the default algorithm for ClassLoader search classes in the JDK.

3, but how does the JVM determine that two classes are the same when searching for a class?

The JVM determines whether the two class is the same, not only to determine whether the two class names are the same, but also to determine whether the same class loader instance is loaded. The JVM does not consider the two classes to be identical until both are satisfied. Even if two classes are the same class byte code, the JVM will consider them to be two different classes if it is loaded by two different ClassLoader instances. For example, a Java class on the network Org.classloader.simple.netclassloadersimple,javac compiled bytecode files Netclassloadersimple.class,classloadera and Classloa Derb these two class loaders and read the Netclassloadersimple.class files, and define Java.lang.Class instances to represent this class, and for the JVM they are two different instance objects, but they are indeed the same byte-code files, if you try to put this CLA When the SS instance generates a specific object for conversion, it throws the Run-time exception java.lang.ClassCaseException, prompting it to be two different types. Now use the instance to verify that the description described above is correct:

1), build a Org.classloader.simple.NetClassLoaderSimple.java class on the Web server

  code is as follows copy code
package org.classloader.simple;
  
public class Netclassloadersimple {
      
  & nbsp Private Netclassloadersimple instance;
  
    public void setnetclassloadersimple (Object obj) {
         this.instance = (netclassloadersimple) obj;
   }
}



The Setnetclassloadersimple method of the Org.classloader.simple.NetClassLoaderSimple class receives an object type parameter and casts it to the Org.classloader.simple.NetCl Assloadersimple type.

2), test two class is the same (Networkclassloader.java)

The code is as follows Copy Code
Package ClassLoader;

public class Newworkclassloadertest {

public static void Main (string[] args) {
try {
Test load class file on network
String Rooturl = "http://localhost:8080/httpweb/classes";
String className = "Org.classloader.simple.NetClassLoaderSimple";
Networkclassloader NCL1 = new Networkclassloader (Rooturl);
Networkclassloader Ncl2 = new Networkclassloader (Rooturl);
class<?> clazz1 = Ncl1.loadclass (className);
class<?> clazz2 = Ncl2.loadclass (className);
Object obj1 = Clazz1.newinstance ();
Object obj2 = Clazz2.newinstance ();
Clazz1.getmethod ("Setnetclassloadersimple", Object.class). Invoke (Obj1, obj2);
catch (Exception e) {
E.printstacktrace ();
}
}

}



First get the binary name of a class file on the network, and then create two instances from the custom ClassLoader Networkclassloader, and load the class according to the network address, The class instance clazz1 and CLAZZ2 are generated after the two ClassLoader instances are loaded, and then the two class instances are generated respectively obj1 and obj2 of the instance objects. The Setnetclassloadersimple method in Clazz1 is then invoked by reflection.

3), view test results



Conclusion: As can be seen from the results, although it is the same class bytecode file, but because it is loaded by two different ClassLoader instances, the JVM considers them to be two different classes.

4, ClassLoader architecture:

To verify the principle of the ClassLoader load class:

Test 1: Print the hierarchy of the ClassLoader class, see the following code:

The code is as follows Copy Code
ClassLoader loader = ClassLoaderTest.class.getClassLoader (); Gets the class loader that loads the Classloadertest.class class
while (loader!= null) {
SYSTEM.OUT.PRINTLN (loader);
Loader = Loader.getparent (); Get a reference to the parent class loader
}
SYSTEM.OUT.PRINTLN (loader);



Print results:



The first line of results shows that the Classloadertest class loader is appclassloader.

The second line shows that the Appclassloader is Extclassloader, that is, Parent=extclassloader.

The third line shows that the Extclassloader is bootstrap ClassLoader, because Bootstrap ClassLoader is not an ordinary Java class, so Extclassloader parent= NULL, so that's why the third row has a null print result.

Test 2: Package the Classloadertest.class into Classloadertest.jar and place it in the extension classloader loading directory (java_home/jre/lib/ext), And then rerun the program, what will be the result?



Print results:



Print result analysis:

Why is the first row the result of Extclassloader?

Because of the ClassLoader delegate model mechanism, when we want to use Classloadertest.class this class, Appclassloader delegates to BOOTSTRCP ClassLoader before attempting to load, BOOTSTRACP ClassLoader found that he did not find, it told Extclassloader, brother, I do not have this class, you go to load look, and then extension ClassLoader take this class to its specified classpath (java_ Home/jre/lib/ext) tried to load, alas, It found that a file such as Classloadertest.class was included in Classloadertest.jar, and then it loaded the found class into memory and generated the class instance object, and finally returned the instance. So the Classloadertest.class class loader is extclassloader. The result of the second row of

is null because the Extclassloader parent class loader is bootstrap ClassLoader.

Test 3: Load Classloadertest.class with BOOTSTRCP ClassLoader, there are two ways:

1, adding-xbootclasspath parameters to the JVM, specifying BOOTSTRCP ClassLoader load the path of the class and append our own jar (Classtestloader.jar)

2, place the class file in the java_home/jre/classes/directory (mentioned above)

Mode 1: (I'm using the Eclipse development tool, using the command line to add the-xbootclasspath parameter after the Java command)

to open the Run Configuration dialog box:



After you have configured the parameters described in the diagram, rerun the program, the result of the production is as follows: (class loading process, only a part of it)

Print results:

The code is as follows Copy Code
[Loaded Java.io.FileReader from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Sun.nio.cs.StreamDecoder from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded java.util.ArrayList from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Java.lang.reflect.Array from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Java.util.Locale from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Java.util.concurrent.ConcurrentMap from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Java.util.concurrent.ConcurrentHashMap from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Java.util.concurrent.locks.Lock from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Java.util.concurrent.locks.ReentrantLock from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded java.util.concurrent.concurrenthashmap$segment from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Java.util.concurrent.locks.AbstractOwnableSynchronizer from C:\Program files\java\jdk1.6.0_22\jre\lib\ Rt.jar]
[Loaded Java.util.concurrent.locks.AbstractQueuedSynchronizer from C:\Program files\java\jdk1.6.0_22\jre\lib\ Rt.jar]
[Loaded Java.util.concurrent.locks.reentrantlock$sync from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Java.util.concurrent.locks.reentrantlock$nonfairsync from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar ]
[Loaded Java.util.concurrent.locks.abstractqueuedsynchronizer$node from C:\Program files\java\jdk1.6.0_22\jre\lib\ Rt.jar]
[Loaded java.util.concurrent.concurrenthashmap$hashentry from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded java.lang.CharacterDataLatin1 from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Java.io.ObjectStreamClass from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded sun.net.www.ParseUtil from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Java.util.BitSet from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded java.net.Parts from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Java.net.URLStreamHandler from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Sun.net.www.protocol.file.Handler from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Java.util.HashSet from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Sun.net.www.protocol.jar.Handler from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Sun.misc.launcher$appclassloader from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded sun.misc.launcher$appclassloader$1 from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded java.lang.SystemClassLoaderAction from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Path C:\Program files\java\jdk1.6.0_22\jre\classes]
[Loaded ClassLoader. Classloadertest from C:\Program files\java\jdk1.6.0_22\jre\classes]
Null//This is the result of printing
C:\Program Files\java\jdk1.6.0_22\jre\lib\resources.jar; C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar;
C:\Program Files\java\jdk1.6.0_22\jre\lib\sunrsasign.jar; C:\Program Files\java\jdk1.6.0_22\jre\lib\jsse.jar;
C:\Program Files\java\jdk1.6.0_22\jre\lib\jce.jar; C:\Program Files\java\jdk1.6.0_22\jre\lib\charsets.jar;
C:\Program Files\java\jdk1.6.0_22\jre\classes;c:\classloadertest.jar
This section is System.out.println (System.getproperty ("Sun.boot.class.path")); This path is the path to the BOOTSTRCP classloader default search class
[Loaded Java.lang.Shutdown from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]
[Loaded Java.lang.shutdown$lock from C:\Program Files\java\jdk1.6.0_22\jre\lib\rt.jar]



Mode 2: After the Classloadertest.jar decompression, placed in the Java_home/jre/classes directory, as shown in the following figure:

Tip: The JRE directory defaults to no classes directory, you need to manually create a



Print results:



From the results, it can be seen that both of the ways to achieve the Classloadertest.class by BOOTSTRCP ClassLoader loaded successfully.

Iv. defining self-classloader

Why do you want to define your own ClassLoader now that the JVM has provided the default class loader?

Because the default classloader provided in Java, only the jar and class in the specified directory are loaded, if we want to load a class or jar in another location, such as: I'm loading a class file on the network, after dynamically loading into memory, To invoke the methods in this class to implement my business logic. In this case, the default ClassLoader is not enough to meet our needs, so we need to define our own classloader.

The class loader that defines itself is divided into two steps:

1. Inherit Java.lang.ClassLoader

2, rewrite the Findclass method of the parent class

Readers may have a question here, the parent has so many methods, why only rewrite the Findclass method?

Because the JDK has helped us implement the ClassLoader search class algorithm in the LoadClass method, the LoadClass method calls the Findclass method to search for classes when the LoadClass method does not search for a class, so we simply rewrite the method. If there are no special requirements, it is generally not recommended to rewrite the LoadClass search class algorithm. The following figure is the LoadClass method for ClassLoader in the API:



Example: Customizing a networkclassloader to load class files on the network

The code is as follows Copy Code
Package ClassLoader;

Import Java.io.ByteArrayOutputStream;
Import Java.io.InputStream;
Import Java.net.URL;

/**
* ClassLoader to load Network class
*/
public class Networkclassloader extends ClassLoader {

Private String Rooturl;

Public Networkclassloader (String rooturl) {
This.rooturl = Rooturl;
}

@Override
Protected class<?> Findclass (String name) throws ClassNotFoundException {
Class clazz = null;//this.findloadedclass (name); Parent class is loaded
if (clazz = = null) {//check whether the class has been loaded
byte[] Classdata = getclassdata (name); Gets the byte-code array of the class file based on the binary name
if (Classdata = = null) {
throw new ClassNotFoundException ();
}
Clazz = defineclass (name, Classdata, 0, classdata.length); Converts a byte-code array of class to an instance of class classes
//}
return clazz;
}

Private byte[] Getclassdata (String name) {
InputStream is = null;
try {
String path = Classnametopath (name);
URL url = new URL (path);
byte[] buff = new BYTE[1024*4];
int len =-1;
is = Url.openstream ();
Bytearrayoutputstream BAOs = new Bytearrayoutputstream ();
while (len = is.read (Buff))!=-1) {
Baos.write (Buff,0,len);
}
return Baos.tobytearray ();
catch (Exception e) {
E.printstacktrace ();
finally {
if (is!= null) {
try {
Is.close ();
catch (IOException e) {
E.printstacktrace ();
}
}
}
return null;
}

private string Classnametopath (string name) {
return Rooturl + "/" + Name.replace (".", "/") + ". Class";
}

}



Test class:

The code is as follows Copy Code
Package ClassLoader;

public class Classloadertest {

public static void Main (string[] args) {
try {
/*classloader loader = ClassLoaderTest.class.getClassLoader (); Get the class loader for classloadertest this class
while (loader!= null) {
SYSTEM.OUT.PRINTLN (loader);
Loader = Loader.getparent (); Get a reference to the parent loader
}
SYSTEM.OUT.PRINTLN (loader);


String Rooturl = "http://localhost:8080/httpweb/classes";
Networkclassloader Networkclassloader = new Networkclassloader (Rooturl);
String classname = "Org.classloader.simple.NetClassLoaderTest";
Class clazz = Networkclassloader.loadclass (classname);
System.out.println (Clazz.getclassloader ());

catch (Exception e) {
E.printstacktrace ();
}
}

}



Print results:



The following figure is the directory structure of the Web server on my machine:



Currently, a common Web server has its own class loader defined to load the class library (Jar or Class) under the specified directory of the Web application, such as Weblogic, Jboss, Tomcat, and so on, I'll take Tomcat as an example to show which class loaders are defined by the Web container:

1. Create a new Web project HttpWeb

2. Create a new classloaderservlettest to print the ClassLoader hierarchy in the Web container

The code is as follows Copy Code
Import java.io.IOException;
Import Java.io.PrintWriter;

Import javax.servlet.ServletException;
Import Javax.servlet.http.HttpServlet;
Import Javax.servlet.http.HttpServletRequest;
Import Javax.servlet.http.HttpServletResponse;

public class Classloaderservlettest extends HttpServlet {

public void doget (HttpServletRequest request, httpservletresponse response)
Throws Servletexception, IOException {

Response.setcontenttype ("text/html");
PrintWriter out = Response.getwriter ();
ClassLoader loader = This.getclass (). getClassLoader ();
while (loader!= null) {
Out.write (Loader.getclass (). GetName () + "");
Loader = Loader.getparent ();
}
Out.write (string.valueof (loader));
Out.flush ();
Out.close ();
}

public void DoPost (HttpServletRequest request, httpservletresponse response)
Throws Servletexception, IOException {
This.doget (request, response);
}

}



3. Configure the servlet and start the service

<?xml version= "1.0" encoding= "UTF-8"?>

The code is as follows Copy Code
<web-app version= "2.4"
Xmlns= "HTTP://JAVA.SUN.COM/XML/NS/J2EE"
Xmlns:xsi= "Http://www.w3.org/2001/XMLSchema-instance"
Xsi:schemalocation= "Http://java.sun.com/xml/ns/j2ee

Http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd ">

<servlet>
<servlet-name>ClassLoaderServletTest</servlet-name>
<servlet-class>ClassLoaderServletTest</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>ClassLoaderServletTest</servlet-name>
<url-pattern>/servlet/ClassLoaderServletTest</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>



4, access to the servlet, get the display results

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.