Home  >  Article  >  Java  >  Java Virtual Machine Learning - Class Loader (ClassLoader)

Java Virtual Machine Learning - Class Loader (ClassLoader)

黄舟
黄舟Original
2017-02-17 10:31:061598browse

Class loader

The class loader (ClassLoader) is used to load class bytecode into the Java virtual machine. Generally speaking, the Java virtual machine uses Java classes as follows: Java source files are converted into Java bytecode files (.class files) after passing through Javac. The class loader is responsible for reading Java bytecode and converting it into an instance of the java.lang.Class class. Each such instance represents a Java class. The actual situation may be more complicated. For example, Java byte code may be dynamically generated through tools or downloaded through the network.


Class and class loader

Although the class loader is only used to implement the loading action of the class, it is used in the Java program The role played in it is far from limited to the class loading stage. For any class, the class loader that loads it and the class itself need to establish its uniqueness in the Java virtual world. To put it more simply, comparing whether two classes are "equal" only makes sense if the two classes are loaded by the same class loader. Otherwise, even if the two classes come from the same class file, as long as it is loaded If the class loaders are different, then the two classes must not be equal. The "equality" referred to here includes the equal method, isAssignableFrom(), isInstance() method and the result returned by the instance keyword of the Class object representing the class.

Class loader classification:



## Mainly divided into Bootstrap ClassLoader, Extension ClassLoader, Application ClassLoader and User Defined ClassLoader.

Bootstrap ClassLoader:

This class loader is implemented in C++ language and is not a subclass of ClassLoader. Mainly responsible for loading all class files stored in JAVA_HOME/jre/lib/rt.jar, or files named rt.jar in the path specified by the -Xbootclasspath parameter.

Extension ClassLoader:

This loader is implemented by sun.misc.Launcher$ExtClassLoader, which is responsible for loading the AVA_HOME/lib/ext directory , or all class libraries in the path specified by the java.ext.dirs system variable.

Application ClassLoader:

This loader is implemented by sun.misc.Launcher$AppClassLoader, which is responsible for loading the jar and directory corresponding to the classpath . Normally this is the default class loader in the program.

Custom class loader (User Defined ClassLoader):

Developers inherit the ClassLoader abstract class and implement their own class loader. Based on the self-developed ClassLoader, it can be used for other than Loading the classpath (such as a jar or binary bytecode downloaded from the Internet), you can also do some small actions before loading the class file, such as encryption, etc.

Parental delegation model:

The hierarchical relationship between class loaders shown in the above figure is called the parent delegation model of class loaders. The parent delegation model requires that in addition to the top-level startup class loader, all other class loaders should have their own parent class loaders. The parent-child relationship between class loaders here is generally not implemented through inheritance. Instead, a combination relationship is used to reuse the code of the parent loader.


public abstract class ClassLoader {

    private static native void registerNatives();
    static {
        registerNatives();
    }

    // The parent class loader for delegation
    private ClassLoader parent;

    // Hashtable that maps packages to certs
    private Hashtable package2certs = new Hashtable(11);
}


双亲委托的工作过程:如果一个类加载器收到了一个类加载请求,它首先不会自己去加载这个类,而是把这个请求委托给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成加载请求(它管理的范围之中没有这个类)时,子加载器才会尝试着自己去加载。

使用双亲委托模型来组织类加载器之间的关系,有一个显而易见的好处就是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,例如java.lang.Object存放在rt.jar之中,无论那个类加载器要加载这个类,最终都是委托给启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类,相反,如果没有双亲委托模型,由各个类加载器去完成的话,如果用户自己写一个名为java.lang.Object的类,并放在classpath中,应用程序中可能会出现多个不同的Object类,java类型体系中最基本安全行为也就无法保证。

类加载器SPI:

java.lang.ClassLoader 类提供的几个关键方法:

loadClass: 此方法负责加载指定名字的类,首先会从已加载的类中去寻找,如果没有找到;从parent ClassLoader[ExtClassLoader]中加载;如果没有加载到,则从Bootstrap ClassLoader中尝试加载(findBootstrapClassOrNull方法), 如果还是加载失败,则抛出异常ClassNotFoundException, 在调用自己的findClass方法进行加载。如果要改变类的加载顺序可以覆盖此方法;如果加载顺序相同,则可以通过覆盖findClass方法来做特殊处理,例如:解密,固定路径寻找等。当通过整个寻找类的过程仍然未获取Class对象,则抛出ClassNotFoundException异常。

如果类需要resolve,在调用resolveClass进行链接。


    protected synchronized Class<?> loadClass(String name, boolean resolve)
	throws ClassNotFoundException
    {
	// First, 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 in order
	        // to find the class.
	        c = findClass(name);
	    }
	}
	if (resolve) {
	    resolveClass(c);
	}
	return c;
    }
findLoadedClass 此方法负责从当前ClassLoader实例对象的缓存中寻找已加载的类,调用的为native方法。



    protected final Class<?> findLoadedClass(String name) {
	if (!checkName(name))
	    return null;
	return findLoadedClass0(name);
    }

    private native final Class findLoadedClass0(String name);


findClass 此方法直接抛出ClassNotFoundException异常,因此要通过覆盖loadClass或此方法来以自定义的方式加载相应的类。


    protected Class<?> findClass(String name) throws ClassNotFoundException {
	throw new ClassNotFoundException(name);
    }


findSystemClass  此方法是从sun.misc.Launcher$AppClassLoader中寻找类,如果未找到,则继续从BootstrapClassLoader中寻找,如果仍然未找到,返回null


    protected final Class<?> findSystemClass(String name)
	throws ClassNotFoundException
    {
	ClassLoader system = getSystemClassLoader();
	if (system == null) {
	    if (!checkName(name))
		throw new ClassNotFoundException(name);
            Class cls = findBootstrapClass(name);
            if (cls == null) {
                throw new ClassNotFoundException(name);
            } 
	    return cls;
	}
	return system.loadClass(name);
    }


defineClass 此方法负责将二进制字节流转换为Class对象,这个方法对于自定义类加载器而言非常重要。如果二进制的字节码的格式不符合jvm class文件格式规范,则抛出ClassFormatError异常;如果生成的类名和二进制字节码不同,则抛出NoClassDefFoundError;如果加载的class是受保护的、采用不同签名的,或者类名是以java.开头的,则抛出SecurityException异常。


protected final Class<?> defineClass(String name, byte[] b, int off, int len,
					 ProtectionDomain protectionDomain)
	throws ClassFormatError
    {
         return defineClassCond(name, b, off, len, protectionDomain, true);
    }

    // Private method w/ an extra argument for skipping class verification
    private final Class<?> defineClassCond(String name,
                                           byte[] b, int off, int len,
                                           ProtectionDomain protectionDomain,
                                           boolean verify)
        throws ClassFormatError
    {
	protectionDomain = preDefineClass(name, protectionDomain);

	Class c = null;
        String source = defineClassSourceLocation(protectionDomain);

	try {
	    c = defineClass1(name, b, off, len, protectionDomain, source,
                             verify);
	} catch (ClassFormatError cfe) {
	    c = defineTransformedClass(name, b, off, len, protectionDomain, cfe,
                                       source, verify);
	}

	postDefineClass(c, protectionDomain);
	return c;
    }
resolveClass 此方法负责完成Class对象的链接,如果链接过,则直接返回。


Common exceptions:

ClassNotFoundException This is the most common exception. The reason for this exception is that the class file was not found when loading the class in the current ClassLoader.

NoClassDefFoundError This exception is because another class referenced in the loaded class does not exist. For example, if A is to be loaded, and B is stolen from A, and B does not exist or the current ClassLoader cannot load B, this exception will be thrown.

LinkageError This exception is more likely to occur in the case of custom ClassLoader. The main reason is that this class has already been loaded in ClassLoader, and repeated loading will cause this exception.


The above is the content of Java virtual machine learning - ClassLoader. For more related content, please pay attention to the PHP Chinese website (www.php.cn) !


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn