JVM Note 7: Class loader and superior delegation mechanism

Source: Internet
Author: User

The virtual machine design team takes the "fully qualified name of a class to describe the binary byte stream of this class" in the class loading phase and puts it outside the Java virtual machine. So that the application can decide for itself how to get the required class, the code block that implements the action is called the "ClassLoader"

There are 2 classes of ClassLoader in Java, one is provided by the system, the other is written by Java application developers

The system provides a class loader that consists of 3 of the following:

1, Start class loader (Bootstarp ClassLoader)

This classloader is controlled by the JVM itself.

Classes that mainly load the JVM's own work: a class library that can be identified by the virtual machine under the path of the%java_home%\lib path or the-xbootclasspath parameter (identified by the filename only, such as: Rt.jar, the name does not conform to the class library will not be loaded into the virtual machine memory

Startup class loader cannot be referenced directly by Java program

2, Extended class loader (Extension ClassLoader)

The class loader is implemented by the static inner class of the Sun.misc.Launcher class Extclassloader

Responsible for loading the Java.ext.dirs parameter (the default value is%java_home%\jre\lib\ext and can be specified by the VM parameter-djava.ext.dirs) specify all class libraries in the path

Developers can use the Extended class loader directly

3, Application class loader (application ClassLoader)

The class loader is implemented by the static inner class of the Sun.misc.Launcher class Appclassloader

Responsible for loading the Java.class.path parameter (the default value is the value of the system environment variable classpath, which can be specified by the VM parameter-djava.class.path) specify all class libraries in the path

System.out.println (System.getproperty ("Java.class.path"));

When this parameter is printed in eclipse, the result is neither the value of the system environment variable classpath, Nor is the VM parameter-djava.class.path the specified value, because each eclipse project contains a. classpath file that actually outputs the value specified in the file

Developers can use the Application class loader directly

Custom class Loader

In addition to the system-supplied ClassLoader, developers can implement their own classloader by inheriting the Java.lang.ClassLoader class and overriding the class's Findclass method

Package com.test;
Import Java.io.ByteArrayOutputStream;
Import Java.io.File;
Import Java.io.FileInputStream;

Import java.io.IOException; public class Myclassloader extends classloader{@Override public class<?> findclass (String name) throws
		undexception {System.out.println ("Use Myclassloader Findclass method."); Name = Com.test.Test//filename = test.class String fileName = name.substring (Name.lastindexof (".")
		+1) + ". Class";
		byte[] bytes = loadClassData ("c:\\seanapp\\" +filename);
	Return defineclass (name, bytes, 0, bytes.length);
		Public byte[] loadClassData (String name) {FileInputStream fileInput = null;
		Bytearrayoutputstream bytesoutput = null;
			try {fileInput = new FileInputStream (new File (name));
			Bytesoutput = new Bytearrayoutputstream ();
			int b = 0;
			while ((b = fileinput.read ())!=-1) {bytesoutput.write (b);
		return Bytesoutput.tobytearray ();
		catch (Exception e) {e.printstacktrace ();
Finally {try {				if (fileInput!= null) fileinput.close ();
			catch (IOException e) {e.printstacktrace ();
	} return null;
		public static void Main (string[] args) {Myclassloader myclassloader = new Myclassloader ();
			try {class< extends object> TestClass = Myclassloader.loadclass ("Com.test.Test");
			Object obj = testclass.newinstance ();
		System.out.println (Obj.getclass (). getClassLoader (). toString ());
		catch (Exception e) {e.printstacktrace (); }
	}
}

Place the Test.class file generated after the test class is compiled into the c:\seanApp\ path

public class Test {public	
	test () {}
}

The results of the operation are:

Sun.misc.launcher$appclassloader@761db1c5

is not very strange. is not loaded by the Myclassloader class, to clarify this point, need to understand ClassLoader's superior delegation mechanism (some books are also referred to as the parental delegation mechanism, the name is called because in the subordinate class loader to hold a higher class loader's global variables, And this global variable has a variable named parent)

The boot ClassLoader, which belongs to the class loader used internally by the JVM, has neither a superior class loader nor a subordinate class loader, and therefore does not comply with ClassLoader's superior delegation mechanism and is only a class loading tool for the JVM, so we start with the Extended class loader and the application class loader

An instance of the Extclassloader class is created in the constructor method of the Sun.misc.Launcher class, and an instance of the Appclassloader class is created with that instance

Public Launcher () {
    //Create extension class loader
    ClassLoader extcl;
    try {
        extcl = Extclassloader.getextclassloader ();
    } catch (IOException e) {
        throw new Internalerror ("could Not create extension class loader ");

    Create the Application class loader
    try {
        loader = Appclassloader.getappclassloader (EXTCL) by using the Extended class loader already created;
    IOException e) {
        throw new Internalerror ("Could not create application class loader");
	......

Extended class loader instantiation process

Static Class Extclassloader extends URLClassLoader {public
	static Extclassloader Getextclassloader () throws ioexception{
		final file[] dirs = Getextdirs ();
		......
		return new Extclassloader (dirs);
		......
	}

	private static file[] Getextdirs () {
		//loading path
		String s = System.getproperty ("Java.ext.dirs");
		......
	}
	Public Extclassloader (file[] dirs) throws IOException {
		//The second parameter specifies the parent class loader, and here is null
		//Description The Extended class loader does not have a superior class
		loader Super (Getexturls (dirs), NULL, factory);
		This.dirs = dirs;
	}
	......
}
The instantiation process of the Application class loader, which determines that the ancestor of the Application class loader is the Extended class loader
Static Class Appclassloader extends URLClassLoader {
	//EXTCL is an instance of the Extclassloader class public
    static ClassLoader Getappclassloader (Final ClassLoader extcl)
			throws ioexception{
        final String s = System.getproperty (" Java.class.path ");
        Final file[] Path = (s = = null)? New File[0]: Getclasspath (s);
        ......
        return new Appclassloader (URLs, EXTCL);
        ......
    }

    Appclassloader (url[] URLs, ClassLoader parent) {
		//The ancestor of the Application class loader is the extended class loader
        super (URLs, parent, factory);
    }
	......
}

Because the custom class loader needs to be implemented by inheriting the ClassLoader class, the constructor of the ClassLoader class is first invoked in the constructor of the custom ClassLoader to see the constructor of the ClassLoader class

Private ClassLoader parent;
private static ClassLoader SCL;

Protected ClassLoader () {This
	(Checkcreateclassloader (), Getsystemclassloader ());
}

Private ClassLoader (Void unused, ClassLoader parent) {
    this.parent = parent;
}

The public static ClassLoader Getsystemclassloader () {
	//SCL creates
    Initsystemclassloader () in the modification method;
	..., return
    SCL;
}

private static synchronized void Initsystemclassloader () {
    if (!sclset) {
        if (SCL!= null)
            throw new Illega Lstateexception ("recursive invocation");
		Gets an instance of the Launcher class
        sun.misc.Launcher L = sun.misc.Launcher.getLauncher ();
        if (l!= null) {
            throwable oops = null;
			The SCL is the Application class loader
            SCL = L.getclassloader ()
            , referring to the constructor of the previous launcher class. ......
            Sclset = true;
        }
    }

The ancestor of the visible custom class loader is the application class loader

If a class loader receives a request for an add-in class, it first does not attempt to load the class itself. Instead, the request is delegated to the parent class loader, which is the case for each class loader, and all loader requests should eventually be routed to the top-level ClassLoader (extended ClassLoader). The subordinate class loader will attempt to load the class itself only when the parent class loader has feedback that it cannot complete the load request (its class loading scope does not find the required class), which is the superior delegation mechanism of the ClassLoader

The virtual machine will call the Loadclassinternal method load class in the ClassLoader class

This are invoked by the virtual machine to load a class.

Private synchronized Class loadclassinternal (String name) throws classnotfoundexception{return LoadClass (name);
Invoking this is equivalent to invoking LoadClass (Name,false).

Public class<?> loadclass (String name) throws ClassNotFoundException {return LoadClass (name, false);}
Subclasses of ClassLoader are encouraged to override Findclass (String),//rather than. Protected synchronized class<?> loadclass (String name, Boolean resolve) throws classnotfoundexception{//
	Check if the class has already been loaded class C = Findloadedclass (name);
			if (c = = null) {try {if (parent!= null) {c = Parent.loadclass (name, false);
			else {c = findbootstrapclassornull (name);
	            } catch (ClassNotFoundException e) {//ClassNotFoundException thrown if class not found From the Non-null parent class loader} if (c = = null)
		    {//If still not found, then invoke findclass into order//to find the class.
	    c = findclass (name);
	} if (resolve) {resolveclass (c);}
return C; }

Through the source code of the LoadClass method, we can see that the class loader first checks whether the class has been loaded, and if it is not loaded, calls the parent class loader to load the class (if the parent class loader is empty, see if the Startup class loader loaded the Class), if the parent class loader fails to load, Call the Findclass method of the lower class loader to load

To ensure that a custom ClassLoader still follows a superior delegation mechanism, JDK recommends implementing a custom class loader by overriding the Findclass method, rather than overriding the LoadClass method (see note 1)

Look at the JDK's description of the Findclass method:

Finds the class with the specified binary name. 
This method should is overridden by class loader implementations
which follow the delegation model for loading classes, And'll is invoked by the
loadclass to checking the
parent class loader for the requested class. The default implementation
throws a ClassNotFoundException

The Resolveclass method in the LoadClass method is also curious, incidentally, to see the effect of this method:

Links the specified class. This (misleadingly named) method is
used by a class loader to link a class. If the Class C has
already been linked, then this method simply returns. Otherwise, the
class is linked as described in the "Execution" chapter of the 
Java Language specification (http://j ava.sun.com/docs/books/jls/).

You can find that the virtual machine will call this method to complete the connection process of the class, and the connection process of the class is as detailed: http://blog.csdn.net/a19881029/article/details/17068191

Viewing the source code for the ClassLoader class shows that many methods are implemented by invoking the local method (the native modifier-modified method)

The advantage of organizing the relationship between class loaders using the superior delegation mechanism is that the Java class, along with its classloader, has a hierarchical relationship of precedence. For example: Java.lang.Object class, which is stored in Rt.jar, no matter which class loader to load this class, will eventually be entrusted to the boot class loader to load, the startup ClassLoader in its search scope can only search the Java.lang.Object class in Rt.jar (see note 2), which can To ensure that the object class is always loaded by the boot ClassLoader from the java.lang.Object in Rt.jar, ensuring uniqueness of the object class (see note 3)

If you do not use the superior delegation mechanism, loaded by the various class loaders, If the user implements a class named Java.lang.Object and loads it with a custom classloader, there will be several different object classes in the system, and the most basic behavior in the Java type System will not be guaranteed and the application will become cluttered.

Note:

1, why JDK does not recommend implementing custom class loaders by overriding the LoadClass method.

Implementing a custom class loader by overriding the Findclass method: When the LoadClass method load class is invoked, because the custom ClassLoader does not override the LoadClass method, the LoadClass method of the ClassLoader class is actually invoked, This method guarantees that if the upper class loader can load the required classes, the loading action is delegated to the superior class loader, and when the upper class loader cannot complete the loading action, the loading action is completed by the Findclass method of the subordinate class loader, which conforms to the class loader superior delegation mechanism.

Implementing a custom class loader by overriding the LoadClass method: When the LoadClass method is called to load a class, the LoadClass method overridden in the custom class loader is called directly to complete the load action. If the overridden LoadClass method does not implement the process of first attempting to delegate the load action to the parent class loader, it will destroy the superior delegation mechanism, which can be broken, but requires a better reason (Jdbc,jndi to break the superior delegation mechanism)

Of course, if in the rewritten LoadClass method first tries to let the superior class loader complete the loading process, then essentially is no no problem, just still awkward, the first is why not use ready-made implementation. Second, if the Superior class loader cannot complete the load action, or the Findclass method to delegate the loading process to the custom ClassLoader, the key problem is that in the ClassLoader class, Findclass is an empty method, That means you still have to rewrite your Findclass method, go around a big circle, and come back, unless you can make sure that the parent class loader can complete the load action, you will not invoke the Findclass method of the custom ClassLoader, but why do you implement your own ClassLoader. So it's right to implement a custom ClassLoader by overriding the Findclass method, but still try it. Implement a custom class loader by overriding the LoadClass method:

2, in the custom class loader, use the DefineClass method to load a java.lang.Object class of my own implementation

Package Java.lang;

Public class Object {public
	object () {}
}

The runtime throws the following exception (the blocked package name):

java.lang.SecurityException:Prohibited Package Name:java.lang

In fact, loading all the "java." The first class throws the exception, which should be protected by the underlying class that the JDK implements for itself

......
if ((name!= null) && name.startswith ("java.") {
	    throw new SecurityException ("Prohibited Package Name:" +
					name.substring (0, Name.lastindexof ('. '));
	}
......

3, compare 2 classes are equal, only if these two classes are loaded by the same class loader is meaningful, otherwise, even if these 2 classes are derived from the same class file, as long as the loading of their class loader is different, these 2 classes must be unequal

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.