Classloader learning notes

Source: Internet
Author: User
As a programming language for real-time compilation, classloader is the basis for Java program running. Although most of the siege Lions like me do not need to deal with classloader at ordinary times, I believe that you are more or less impressed with classnotfoundexecption and noclassdeffounderror. These two classes are closely related to classloader.
First, the Java Virtual Machine implements three class loaders: 1. bootstrap Class Loader: loads the Class Libraries under <java_runtime_home>/lib, which are implemented by local code and mainly used to initialize the Java virtual machine, which is part of the local implementation of the Java Virtual Machine. 2. Standard extension class loader: loads the Class Libraries under <java_runtime_home>/lib/EXT, which are implemented by Java and can be used by developers. 3. system Class Loader: loads the class libraries under the classpath path. Generally, the class libraries written by developers are also loaded by this loader (the bin folder is also in the classpath path ), classloader. getsystemclassloader () obtains the index of the loader. In addition, the Class Loader compiled by the developer is a custom class loader.
Second, parent-parent delegation mechanism: Apart from starting class loaders, other three types (standard extension class loaders, system class loaders, and custom loaders) are directly or indirectly inherited from Java. long. classloader. The following is the implementation code of classloader (jdk1.6 ):
// The parent class loader for delegation private classloader parent;/*** creates a new class loader using the specified parent class loader for * delegation. ** <p> if there is a security manager, its {@ link * securitymanager # checkcreateclassloader () * <tt> checkcreateclassloader </tt>} method is invoked. this may result in * A security exception. </P> ** @ Param parent * the parent class loader ** @ throws securityexception * if a security manager exists and its * <tt> checkcreateclassloader </tt> method doesn' t allow creation * Of a new class loader. ** @ SINCE 1.2 */protected classloader (classloader parent) {This (checkcreateclassloader (), parent );} /*** creates a new class loader using the <tt> classloader </tt> returned by * The method {@ link # getsystemclassloader () * <tt> getsystemclassloader () </tt>} as the parent class loader. ** <p> if there is a security manager, its {@ link * securitymanager # checkcreateclassloader () * <tt> checkcreateclassloader </tt>} method is invoked. this may result in * A security exception. </P> ** @ throws securityexception * if a security manager exists and its * <tt> checkcreateclassloader </tt> method doesn' t allow creation * Of a new class loader. */protected classloader () {This (checkcreateclassloader (), getsystemclassloader (); // systemclassloader is used as parent by default}
/*** Loads the class with the specified <a href = "# name"> binary name </a>. the * default implementation of this method searches for classes in the * following order: ** <p> <ol> ** <li> <p> invoke {@ link # findloadedclass (string)} to check if the class * has already been loaded. </P> </LI> ** <li> <p> invoke the {@ link # loadclass (string) <tt> loadclass </tt>} Method * on the parent class loader. if Parent is <tt> null </tt> the class * loader built-in to the virtual machine is used, instead. </P> </LI> ** <li> <p> invoke the {@ link # findclass (string)} method to find the * class. </P> </LI> ** </OL> ** <p> If the class was found using the above steps, and the * <tt> resolve </tt> flag is true, this method will then invoke the {@ link * # resolveclass (class )} method on the resulting <tt> class </tt> O Bject. ** <p> subclasses of <tt> classloader </tt> are encouraged to override {@ link * # findclass (string)}, rather than this method. </P> ** @ Param name * The <a href = "# name"> binary name </A> of the class ** @ Param resolve * If <tt> true </tt> then resolve the class ** @ return the resulting <tt> class </tt> Object ** @ throws classnotfoundexception * If the class cocould not be found */protected synch Ronized class <?> Loadclass (string name, Boolean resolve) throws classnotfoundexception {// first, check if the class has already been loadedclass c = findloadedclass (name); // find the loaded class, if it has already been loaded, there is no need to load it again
// If this check is removed, linkageerrorif (C = NULL) {try {If (parent! = NULL) {// delegate the parent loader to load Class C = parent. loadclass (name, false);} else {// If parent = NULL, we consider the parent loader as the startup Class Loader 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 in order // to find the class. C = findclass (name); // if the parent class loader fails to load, the sub-class will implement it.} If (RESOLVE) {resolveclass (C ); // link} return C ;}

From the implementation of the loadclass function, we find that when the loader is loaded, it will first delegate the parent class loader to try to load. This is the parent-parent delegation mechanism.

For example, in code, bootstrapclassloader is not the parent of extensionclassloader (in fact, bootstrapclassloader is implemented in the local language, so the parent of extensionclassloader is null ), logically, parent = NULL is equivalent to parent = bootstrapclassloader. The parent-child relationship of the four types of loaders is as follows:

Therefore, we can use classloader. getsystemclassloader (). getparent () to obtain the index of extensionclassloader. It is worth mentioning that the parent-parent delegation mechanism can better meet the needs of most Java applications. However, in some special scenarios, you can modify the parent-parent delegation mechanism to improve performance. For example, you can load classes by the current loader first, failed to load and then delegate the parent class loader to load. Third, each classloader corresponds to a namespace, and JVM uniquely identifies a class through this namespace + the full name of the class (including package name. Therefore, pay attention to the following issues: 1. the same class can be loaded repeatedly. If you use two different class loaders to load the same class, then there are two identical class definitions in JVM (their namespaces are different ). 2. From the first question, the problem is that the same class is loaded by different class loaders, which is different for JVM. Therefore, classcastexception may occur, for example:

Classa A = new classa (); // classa load classa B = NULL via classloader1; // classa load B = (classa) A via classloader2; // throw classcastexception

3. because the Parent-Child delegation mechanism exists, classloadera is executed. loadclass ("com. example. classa ") the loaded classa is not necessarily loaded by classloadera, or it may be loaded by its parent loader, for example (systemclassloader ). In this case, classloadera becomes the initial class loader of classa, while systemclassloader is the definition Class Loader. The class namespace is defined by the definition class loader. Fourth, Java Dynamic Loading when the project has some special requirements, such as: 1. during app running, you need to obtain the latest class/JAR file from the network and dynamically update it. apps have high security requirements and perform additional encryption operations on the class/jar files, so that the common class loaders cannot parse class/java files and other special circumstances, you need to consider dynamic loading. common Java Dynamic Loading solutions include class. forname and custom class loader.
A common case of using class. forname for dynamic loading is JDBC driver loading.
The class. forname function has two types of overloading:

Public static class <?> Forname (string classname) throws classnotfoundexception {return forname0 (classname, true, classloader. getcallerclassloader (); // class is called by default. the classloader of the caller of the forname function is loaded (classloader parameter = classloader. getcallerclassloader () and complete the connection and initialization (initialize parameter = true ). } Public static class <?> Forname (string name, Boolean initialize, classloader loader) throws classnotfoundexception {If (loader = NULL) {securitymanager Sm = system. getsecuritymanager (); If (SM! = NULL) {classloader CCL = classloader. getcallerclassloader (); If (CCL! = NULL) {SM. checkpermission (securityconstants. get_classloader_permission) ;}} return forname0 (name, initialize, loader );}

A common case of using a custom classloader to implement dynamic loading is to use dynamic code updates (maybe this feature will be available on a specific platform such as cloud OS in the future ). In theory, the standard extension class loader and system class loader can also be dynamically loaded. However, in general, the files in the class scan paths (<Java-runtime-Home>/lib/EXT, and classpath) of these two loaders are not changed, so they are generally used in static mode. It is relatively easy to implement a custom Class Loader according to Sun's suggestions. Inherit classloader and override findclass functions (in Sun's standard implementation, both the standard extension class loader and the system class loader are inherited from urlclassloader, which is a descendant class of classloader. Therefore, I personally think that the custom Class Loader inherits from urlclassloader is also a good choice): the following code Excerpt from: http://www.ibm.com/developerworks/cn/java/j-lo-classloader/

public class FileSystemClassLoader extends ClassLoader {     private String rootDir;     public FileSystemClassLoader(String rootDir) {         this.rootDir = rootDir;     }     protected Class<?> findClass(String name) throws ClassNotFoundException {         byte[] classData = getClassData(name);         if (classData == null) {             throw new ClassNotFoundException();         }         else {             return defineClass(name, classData, 0, classData.length);         }     }     private byte[] getClassData(String className) {         String path = classNameToPath(className);         try {             InputStream ins = new FileInputStream(path);             ByteArrayOutputStream baos = new ByteArrayOutputStream();             int bufferSize = 4096;             byte[] buffer = new byte[bufferSize];             int bytesNumRead = 0;             while ((bytesNumRead = ins.read(buffer)) != -1) {                 baos.write(buffer, 0, bytesNumRead);             }             return baos.toByteArray();         } catch (IOException e) {             e.printStackTrace();         }         return null;     }     private String classNameToPath(String className) {         return rootDir + File.separatorChar                 + className.replace('.', File.separatorChar) + ".class";     }  }
Among the classloader functions worth noting are: 1. loadclass function, which implements the check of loaded classes and the implementation of the parent-parent delegation mechanism. Do not overwrite this function if there is no such function. 2. findclass function. This function is called by the loadclass function to find the bytecode (. class file). If the corresponding bytecode is not found, classnotfoundexception is thrown. 3. defineclass. This function is called by the findclass function, which resolves bytecode and generates the corresponding class. If the parsing fails, the system throws noclassdeffounderror. We do not recommend overwriting. Although Java Dynamic Loading brings advantages, developers can achieve many functions, but it also has some side effects, because the local app is dynamic, the static part cannot call the dynamic update class in the usual way. Therefore, the following two methods are generally required: 1. the interface, the Dynamically Loaded class always implements the specified interface, and the static part calls the Dynamically Loaded class through the interface. 2. reflect: Call a Dynamically Loaded class by specifying the class name and function name (member name. Fifth, the thread context loader can be set and obtained by the thread. setcontextclassloader function and the thread. getcontextclassloader function. The thread context class loader can be any loader instance inherited from classloader, either a system class loader or a custom class loader. By default, the thread inherits the contextclasloader of its parent thread, while the contextclassloader of the Java initial thread is the system class loader. Therefore, if not set, all thread context class loaders are system class loaders. Java provides many Service Provider Interfaces (SPI) to improve openness ). In these circumstances, the parent-parent delegation mechanism has encountered problems. Take JAXP (Java XML parsing API) as an example:Javax. xml. parsers (jaxp spi interface) is defined by the Java core library and loaded by the startup Class Loader. The corresponding implementation of Apache
Xercers exists in the classpath path and is loaded by the system class loader. According to class. the default Implementation Rules of the forname function, Java. XML. classes in the parsers package will use the start class loader to load the Apache implementation class, but the start class loader is the parent class loader of the system class loader, And the start class loader will not, the system loader cannot be called. Therefore, loading may fail.
To solve these problems, a context loader is introduced from Java so that the SPI interface can load its implementation class.
6. Java bytecode formatFindclass in classloader is ultimately implemented by native code. I have never seen how to resolve the. Class file to class, so I found some other materials.
The Java bytecode format is described in the JVM virtual machine specification.       
Classfile {U4 magic; // magic number, fixed to 0 xcafebabe U2 minor_version; // sub-version number, generally 0x0 U2 major_version; // main version number, determined by the Java version number, java1.5 = 0x31, java1.6 = 0x32, java1.7 = 0x33 U2 constant_pool_count; // The length of the constant pool cp_info constant_pool [constant_pool_count-1]; // constant pool U2 access_flags; // access flag, Private, package, public... u2 this_class; // This class is the valid index U2 super_class in the constant pool; // This class is the valid index U2 interfaces_count in the constant pool; // Number of Implemented interfaces U2 interfaces [interfaces_count]; // The implemented interface pool U2 fields_count; field_info fields [fields_count]; // The number of members and the member pool U2 methods_count; method_info methods [methods_count]; // Method Quantity and method pool U2 attributes_count; attribute_info attributes [attributes_count]; // attribute quantity and attribute pool}


For details, see: Java Virtual Machine specifications (iii) class file format 7. After a class is loaded, the JVM starts to execute the link operation (classloader. resolveclass () is a link class ). Link Operations are divided into three small steps: 1. Check: Check operations to ensure that Java bytecode is correct .. A classfile can be an invalid file (such as an empty file) or a Java version (the Java Virtual Machine cannot parse the class file of java1.6 ). If the verification succeeds, the link will continue; otherwise, a java. Lang. verifyerror error will be thrown. 2. Preparation: allocate memory space for static variables of the class and initialize the default value. 3. Resolution: The Java classes to be linked generally contain references to other classes and interfaces (including parent classes, Implemented interfaces, method parameters, and returned values ). The purpose of parsing is to ensure that these classes can be found. Common parsing policies include recursive parsing and time-based parsing. Recursive parsing involves recursively loading dependent interfaces and classes. The more commonly used policy is parsing when the class is actually needed. After the connection is successful, the JVM will be initialized next. Initialization mainly involves executing static code blocks and initializing static fields. The preparation steps for initializing static domains are different from those for Link Operations. Take the following code as an example:

private static int number = 1;

In fact, the heap allocates 4 bytes of space and initializes it to 0;

The initial static domain is to set the allocated space to 1. Execute the static code block. This is the first time that the code in the class file is executed. To sum up, after JVM loading, linking, and initializing, a class file is converted into a subclass of Java. Long. Class and can be executed in JVM. References: Analysis of Java class Loading Principles

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.