JVM basis - the class loader delegation model with parents

I. Introduction

  This is the JVMfifth in the series blog, and it is the last one, finish this blog, I will temporarily stop JVMlearning, I began studying other aspects of the. This blog just to talk about JVMclass 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 classbyte code to be executed, JVMthe interpreter can only recognize byte code can not be executed Javasource 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 classfile which was read to JVMthe 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 Classcreate objects Testobjects 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 Testcreation, and the intanceofstatement Testis a JVMclass 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 Javaimplementation language, but by the C++realization of the (HotSpot virtual machine), which is responsible for loading %JAVA_HOME%\libclasses directory, for example String, Integer, HashMapwhich are placed in this category ....... directory, so It is loaded by the boot class loader. In addition, JVMalso provides a configuration parameter -Xbootclasspath, the class files (e.g., under the directory specified by the jarpacket, classfile) will be loaded boot class loader. Since the class loader is C++implemented, it does not belong to the Javapart, but a part of the virtual machine, can not Javadirectly reference code. The following code can attempt to obtain Stringthe class of the class loader, i.e. the boot class loader, but the result is output null, because it is not Javaa 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 Javaimplemented, 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\extthe class directory. Since this is a class loader Java, it can be implemented directly in the Javareferenced program. We can a %JAVA_HOME%\lib\extclass of directory Classobjects 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 Javaimplementation language, the implementing class is sun.misc.Launcher$AppClassLoaderfrom $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 CLASSPATHof the current path where included). So, when we write your own Javacode does not specify the class loader, this loader is used to load default. Since the class loader is Javaimplemented, 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 ClassLoaderclass, then override these methods can be. For the Javarealization 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 classfile, is converted into a byte array, and then call the parent class defineClassmethod to convert a byte array Classobject 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 ClassLoaderclass, 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 ClassLoaderkind of loadClassmethod 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.Stringclass, 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 JVMspecification mandated, but a recommended strategy. So we can not follow this model when writing your own class loader, such as rewriting loadClassmethod 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 Javasome 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"

Guess you like

Origin www.cnblogs.com/tuyang1129/p/12515069.html