A detailed analysis of the Java ClassLoader principle

Source: Internet
Author: User

First, what is ClassLoader?

As we all know, when we write a Java program, not whether it is CS or BS application, is a complete Java application organized by several. class files, when the program is run, it calls an entry function of the program to invoke the relevant functions of the system, and these functions are encapsulated in different class files, so it is often necessary to call from this class file another class file method, a system exception is thrown if the other file does not exist. When the program starts, it does not load all the class files used by the program at once, but instead dynamically loads a class file into memory according to the needs of the program through the Java class loading mechanism (ClassLoader), so that only the class file is loaded into memory To be referenced by the other class. So ClassLoader is used to dynamically load class files into memory.

Second, the Java default provides three ClassLoader
  1. Bootstrap ClassLoader: Called the startup ClassLoader, is the topmost class loader in the Java class load hierarchy.responsible for loading the core libraries in the JDK, such as: Rt.jar, Resources.jar, Charsets.jar, etc., you can get where the ClassLoader loaded the relevant jar or class file from the following program:
    url[] urls = Sun.misc.Launcher.getBootstrapClassPath (). Geturls ();  for (int i = 0; i < urls.length; i++) {      System.out.println (Urls[i].toexternalform ());  }

    The following are the results of 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 known by looking up the sun.boot.class.path System Properties.

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

    Printing results: 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

  2. Extension ClassLoader: called the Extension class loader, is responsible for loading the Java Extension Class library, loading all the jars under java_home/jre/lib/ext/by default.
  3. app ClassLoader: Called the system ClassLoader, is responsible for loading all the jar and class files in the application Classpath directory.

Note: In addition to the three classloader provided by the Java default, users can also define their own classloader as needed. These custom classloader must inherit from the Java.lang.ClassLoader class, as well as the additional 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 underlying is written in C + +, embedded in the JVM kernel, when the JVM starts, Bootstrap ClassLoader also with the boot, responsible for loading the core class library, and constructs the extension ClassLoader and the app ClassLoader class loader.

Three, the ClassLoader load class principle 1, the principle introduction

ClassLoader uses a parent- delegate model to search for classes, and each ClassLoader instance has a reference to the ClassLoader (not an inherited relationship, a contained relationship), and the virtual machine's built-in ClassLoader (Bootstrap ClassLoader) itself does not have a parent classloader, but can be used as a parent ClassLoader for other ClassLoader instances. When a ClassLoader instance needs to load a class, it attempts to search for a class by itself, delegating the task to its parent classloader, which is checked from top to bottom, first by the topmost class loader bootstrap classloader trying to load, If not loaded, the task is forwarded to the extension ClassLoader attempt to load, if not loaded, then to the app ClassLoader to load, if it is not loaded, then return to the initiator of the delegate, It loads the class into 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 generates a class definition, loads it into memory, and finally returns the class instance object in memory.

2. Why use parents to entrust this model?

Because this avoids repeated loading, there is no need for the child classloader to load again when the parent has loaded the class. Considering the security factors, let's imagine that if we don't use this delegate pattern, we can use a custom string at any time to dynamically replace the type defined in the Java Core API, so there's a very big security risk, and the way that parents delegate, you can avoid this situation, Because the string has been loaded by the Boot class loader (BOOTSTRCP ClassLoader) at startup, the user-defined ClassLoader can never load a string that he writes, Unless you change the default algorithm for the ClassLoader search class in the JDK.

3, but the JVM in the search class, and how to determine the two class is the same?

The JVM determines whether the two classes are 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 considers the two classes to be the same only if the two are both satisfied. Even if the two class is the same class bytecode, if it is loaded by two different ClassLoader instances, the JVM will consider them to be two different classes. such as a Java class on the network Org.classloader.simple.netclassloadersimple,javac compiled after the generation of bytecode files Netclassloadersimple.class,classloadera and Classloa Derb these two classloader and read the Netclassloadersimple.class file and define the Java.lang.Class instance to represent this class, for the JVM, they are two different instance objects, but they are really the same byte-code file, if you try to put this CLA When a SS instance generates a specific object for conversion, it throws a run-time exception java.lang.ClassCaseException, suggesting that it is two different types. Now use the example to verify that the above description is correct:

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

Package org.classloader.simple;  public class Netclassloadersimple {      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 argument and casts it to org.classloader.simple.NetCl The assloadersimple type.

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

package ClassLoader; public class Newworkclassloadertest {public static void main (string[] args) {try {//Test load Network              class file 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 separately based on the network address. Then we get the class instance clazz1 and CLAZZ2 generated by these two ClassLoader instances, and finally generate the concrete instance object Obj1 and Obj2 for each of the two class instances, The Setnetclassloadersimple method in Clazz1 is then called through reflection.

3), view test results

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

4, ClassLoader system structure:

Verify the principle of the ClassLoader load class:

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

ClassLoader loader = ClassLoaderTest.class.getClassLoader ();    Gets the class loader that loads Classloadertest.class this class  while (loader! = null) {      System.out.println (loader);      Loader = Loader.getparent ();    Get the parent ClassLoader reference  }  System.out.println (loader);

Printing results:

The first line shows that the class loader for classloadertest is appclassloader.

The second line shows that the appclassloader is extclassloader, i.e. Parent=extclassloader.

The third line shows that the Extclassloader is bootstrap ClassLoader, because Bootstrap ClassLoader is not a common Java class, so Extclassloader parent= NULL, so the third row is printed as null for this reason.

Test 2: package The Classloadertest.class into Classloadertest.jar, put it in extension classloader load directory (java_home/jre/lib/ext), And then rerun the program, what will be the results?

Printing results:

Print Results Analysis:

Why is the result of the first line Extclassloader?

Because of the ClassLoader mechanism of the Commission, when we want to use Classloadertest.class this class, appclassloader before attempting to load, the first delegate to BOOTSTRCP ClassLoader, BOOTSTRACP ClassLoader found himself not found, it told Extclassloader, brother, I do not have this class here, you go to load see, and then extension ClassLoader take this class to its specified classpath (java_ Home/jre/lib/ext) trying to load, alas, It finds that a file such as Classloadertest.class is included in the Classloadertest.jar, and then it loads the found class into memory and generates the class instance object for that type, and finally returns the instance. So the Classloadertest.class class loader is extclassloader.

The result of the second row is null because the parent classloader of Extclassloader is Bootstrap ClassLoader.

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

1. Add the-xbootclasspath parameter to the JVM, specify the path to the BOOTSTRCP ClassLoader load class, and append our own jar (Classtestloader.jar)

2. Put the class file in the java_home/jre/classes/directory (mentioned above)

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

Open the Run Configuration dialog box:

After configuring the parameters described in, rerun the program, the results are as follows: (The process of class loading, only a part of the pick)

Printing results:

[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")); Printed out. This path is the path to the default search class for BOOTSTRCP ClassLoader [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 extracting the Classloadertest.jar, put it in the Java_home/jre/classes directory, as shown in:

tip:The JRE directory does not have a classes directory by default, you need to manually create a

Printing results:

As can be seen from the results, both approaches have been implemented to successfully load the Classloadertest.class from the BOOTSTRCP ClassLoader.

Iv. Define your own ClassLoader

Since the JVM already provides the default ClassLoader, why do you define your own classloader?

Because of 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 want to load a class file on the network, by dynamically loading into memory, To invoke the methods in this class to implement my business logic. In this case, the default classloader will not meet our needs, so we need to define our own classloader.

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

1. Inheriting Java.lang.ClassLoader

2. Overriding the Findclass method of the parent class

The reader may have doubts here, there are so many ways for the parent class, why just rewrite the Findclass method?

Because the JDK has already implemented the ClassLoader search class algorithm in the LoadClass method, the LoadClass method calls the Findclass method to search for the class when the class is not found in the LoadClass method, so we just need to rewrite the method. If there are no special requirements, it is generally not recommended to rewrite the LoadClass search class algorithm. Is the LoadClass method for ClassLoader in the API:

Example: Customizing anetwork ClassLoader to load a class file on the Web

Package ClassLoader;  Import Java.io.ByteArrayOutputStream;  Import Java.io.InputStream;  Import Java.net.URL;      /** * Load Network class ClassLoader */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);  The parent class has loaded//if (clazz = = null) {//check if the class has been loaded byte[] Classdata = getclassdata (name);              According to the binary name of the class, obtain the byte-code array of the class file if (Classdata = = null) {throw new ClassNotFoundException ();  } clazz = defineclass (name, Classdata, 0, classdata.length);      Converts a class's byte-code array into an instance of class (/} 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:

Package ClassLoader;  public class Classloadertest {public      static void Main (string[] args) {          try {              /*classloader loader = classload ErTest.class.getClassLoader ();  Get the class loader for this class classloadertest             while (loader! = null) {                 System.out.println (loader);                 Loader = Loader.getparent ();    Obtain 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 ();}}  }

Printing results:

Is the directory structure of the Web server on my machine:

Now the common Web server has defined its own class loader, for loading the Web application under the specified directory of the class library (Jar or class), such as: Weblogic, Jboss, Tomcat, and so on, I use Tomcat as an example to show that the Web container defines which class loader:

1. Create a new Web project HttpWeb

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

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, Httpservletre          Sponse 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 () + "<br/>");          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"?>  <web-app version= "2.4"       xmlns= "http://java.sun.com/xml/ns/ Java ee "       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 servlet for display results

A detailed analysis of the Java ClassLoader principle

Related Article

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.