I. Introduction
This is the JVM
fifth in the series blog, and it is the last one, finish this blog, I will temporarily stop JVM
learning, I began studying other aspects of the. This blog just to talk about JVM
class loaders, as well as the parent class loader delegation model.
Second, the text
2.1 What is the class loader
First of all we need to know one thing, and that is what is the class loader? We all know that our code needs to be compiled to class
byte code to be executed, JVM
the interpreter can only recognize byte code can not be executed Java
source code. The procedures are performed in memory, so to be able to execute bytecode, it will need to be read into memory. The bytecode is read into the working memory, a class loader is accomplished. The class loader provided fully qualified class name (package name + class name), the class to find the corresponding path class
file which was read to JVM
the method area managed, so as to execute code instructions therein, accessed class data. About class loading mechanism, you can refer to this blog: the JVM base - loading process analysis class .
For the class loader, you need to pay attention to a problem. Each class is determined with uniqueness and a class loader itself. What does it mean? That is, if the bytecode of a class, using two different class loader to load, for the JVM, the loading will be identified as these two different two classes . For example, we have a class Test
, the class loader creates a custom to load it, and custom class loader obtained Class
create objects Test
objects t
(reflection), running at the time t instanceof Test
, obtained will be false
. Because this object is achieved by a custom class loader loads the Test
creation, and the intanceof
statement Test
is a JVM
class loaded by Test
, for JVM
, this is two different classes. In addition, for the class have the same fully qualified name of the same class loader will load only once, not repeated load .
2.2 Classification class loader
In Java
, the class loader is generally divided into four categories, namely:
- Boot class loader (Bootstrap ClassLoader);
- Extension class loader (Extension ClassLoader);
- Application class loader (Application ClassLoader);
- Custom class loader (User ClassLoader);
Here's an overview of what each of these four different class loader.
(1) Start class loader (Bootstrap ClassLoader)
Start class loader is not the Java
implementation language, but by the C++
realization of the (HotSpot virtual machine), which is responsible for loading %JAVA_HOME%\lib
classes directory, for example String
, Integer
, HashMap
which are placed in this category ....... directory, so It is loaded by the boot class loader. In addition, JVM
also provides a configuration parameter -Xbootclasspath
, the class files (e.g., under the directory specified by the jar
packet, class
file) will be loaded boot class loader. Since the class loader is C++
implemented, it does not belong to the Java
part, but a part of the virtual machine, can not Java
directly reference code. The following code can attempt to obtain String
the class of the class loader, i.e. the boot class loader, but the result is output null
, because it is not Java
a part of:
public static void main(String[] args) {
ClassLoader c = String.class.getClassLoader();
System.out.println(c); // 输出null
}
(2) extended class loader (Extension ClassLoader)
Extension class loader is Java
implemented, the implementation class is sun.misc.Launcher$ExtClassLoader
(name can be seen that this is an internal class), this class loader is responsible for loading %JAVA_HOME%\lib\ext
the class directory. Since this is a class loader Java
, it can be implemented directly in the Java
referenced program. We can a %JAVA_HOME%\lib\ext
class of directory Class
objects to get the class loader, this may be obtained by the following method (a method based parent delegation model, explained later):
public static void main(String[] args) {
// 获得自己写的类的加载器
ClassLoader c = Main.class.getClassLoader();
// Main加载器的父加载器就是扩展类加载器
ClassLoader c2 = c.getParent();
// 输出:sun.misc.Launcher$ExtClassLoader@eed1f14
System.out.println(c2);
}
(3) application class loader (Application ClassLoader)
This type of loading is the Java
implementation language, the implementing class is sun.misc.Launcher$AppClassLoader
from $
can be seen that symbol, which is an internal class. It is responsible for loading the class path ( CLASSPATH
) in the library, and our code also belong (in the path CLASSPATH
of the current path where included). So, when we write your own Java
code does not specify the class loader, this loader is used to load default. Since the class loader is Java
implemented, it may be referenced in our code, referenced as follows:
public static void main(String[] args) {
// 方式1:使用自定义类的Class对象获得
ClassLoader c1 = Main.class.getClassLoader();
// 方式2:使用ClassLoader类的getSystemClassLoader方法获得
ClassLoader c2 = ClassLoader.getSystemClassLoader();
// 输出:sun.misc.Launcher$AppClassLoader@18b4aac2
System.out.println(c1);
// 输出:true
System.out.println(c1 == c2);
}
(4) a custom class loader (User ClassLoader)
If necessary, we can write your own class loader, and I have written class loader is called a custom loader. Writing custom class loader is very simple: inherited ClassLoader
class, then override these methods can be. For the Java
realization of the class loader, which is invoked loadClass()
method for class loading, so we can override this method, but this practice is not recommended, because it is easy to destroy the class loading mechanism (after the parents will be referred to delegate model). The best practice is to override the findClass()
method that will loadClass()
be called in. In the findClass()
method, the read to load the class class
file, is converted into a byte array, and then call the parent class defineClass
method to convert a byte array Class
object is returned, as shown below:
// 自定义类加载器,实现ClassLoader
class MyClassLoader extends ClassLoader {
//指定class文件的路径路径
private String path;
public MyClassLoader(String classPath) {
path = classPath;
}
/**
* 重写findClass方法
* @param name 是我们这个类的全路径
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class log = null;
// 获取该class文件字节码数组
byte[] classData = getData();
if (classData == null) {
throw new ClassNotFoundException("Class Not Found");
}
// 将class的字节码数组转换成Class类的实例,并返回
return defineClass(name, classData, 0, classData.length);;
}
/**
* 读取class,将字节码转换成字节数组
* @return
*/
private byte[] getData() {
// 省略读取的代码
// 普通IO读取即可
}
}
2.3 parent delegation model
Relationship between the above image corresponding to the delegation model is called the parent class loader. For each class loader, loader has a parent (except the boot class loader). When the class loader to load a class, it will be the first delegate to its parent class loader to load, if the parent also has a parent loader loader, continue commissioned up until the start class loader. Start class loader tries to load this class, if the class in their own directory under management, and has not yet been loaded, loaded successfully, or failed to load; if failed to load, then to the lower extension class loader to load, the extension class loader performs the same operation. Overall, the parent delegation model is the first class to the parent class loader tries to load, if the load fails, then be loaded by subclasses, each layer is so . In actual implementation, this parent-child relationship is not achieved by the inheritance, but by the combination achieved in ClassLoader
class, there is a property called parent
, is a pointer to its parent loader references (before the extension class loader code is obtained in this way).
Here we are ClassLoader
kind of loadClass
method source code, look at the specific implementation code parent delegation model:
// name为类的全限定类名
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
// 这个重载方法被上面的方法调用
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
// 对以下代码进行多线程同步
synchronized (getClassLoadingLock(name)) {
// 首先,判断这个类是否已经被加载
Class<?> c = findLoadedClass(name);
// c为null表示还没有被加载,则进行加载
if (c == null) {
long t0 = System.nanoTime();
try {
// 此处是双亲委托机制的关键
// 如果当前加载器有父加载器
if (parent != null) {
// 调用父加载器的loadClass对类进行加载
c = parent.loadClass(name, false);
} else {
// 若没有父类加载器,则调用引导类加载器尝试加载
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// 此时加载失败将抛出异常,提示类找不到
// 不需要处理,继续执行
}
// c为null表示调用上层类加载器加载失败
if (c == null) {
long t1 = System.nanoTime();
// 调用当前类加载器的findClass进行加载
// 所以自定义类加载器推荐重写findClass方法
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
By the above code, we can clearly see how the parents delegate mechanism is implemented. That this mechanism what good is it? Use parent delegation mechanism ensures that class is being loaded condition satisfies a first class loader. For a class loader for each class will only be loaded once, so the load will not cause the same class multiple times, a situation to be loaded or a different class loader class. Said before, the only class is determined by its own and its class loader to load, the delegation model using the parent class is good to avoid loading a plurality of loaders, the same does not result in equivalent in memory the type. For example, we define a java.lang.String
class, if there is no parent delegation model, two occurred in memory String
, but in our view there is only one, at this time will cause the program to generate an error inexplicable. The parent delegation model to ensure that the class of the same name this way is never loaded to run, so our own definition of the class will never be able to use the same name, although the compiler can (where you can try your own).
Of course, parents are not delegated model JVM
specification mandated, but a recommended strategy. So we can not follow this model when writing your own class loader, such as rewriting loadClass
method covered by this mechanism. But if it is not necessary, or not recommended.
Third, the summary
And parents about the class loader delegation model would want to say it. The two parts of the face made a fairly detailed description, I believe that would be after reading Java
some of the relevant features are more in-depth understanding, we usually can solve some doubts.
Fourth, the reference
- "In-depth understanding of the Java Virtual Machine"