ClassLoader心得

Posted sten

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ClassLoader心得相关的知识,希望对你有一定的参考价值。

   
      我们都知道,jvm执行的代码,都是通过jvm加载系统加入的。加载系统的第一步是通过ClassLoader加载class二进制信息,jvm规范中并没有规定class的来源类型,这就给jvm的实现这块很大的灵活。可以放在数据库里,可以放在网络的其他地方(以前的applet),zip文件等。现在大多数都是放在zip包里,我们引入其他class都是通过引入zip包的形式。
 
   ClassLoader关系结构如下
          BootStrap ClassLoader
               |
          Extension ClassLoader
               |
          System ClassLoader
               |
          Custom  ClassLoader
 
BootStrap ClassLoader 是由C++编写,虚拟机的一部分,只用来加载核心类。负责加载目录[JAVA_HOME]/bin下的jar,或者被参数 -DXbootclasspath说指定目录的jar,并且是jvm识别的。
 
Extension ClassLoader是java编写的,对应java系统中的ExtClassLoader类,负责加载java里的ext包里的类。
 
System ClassLoader 也是由java编写,对应系统中的AppClassLoader类,负责加载应用中的代码。
 
Custom ClassLoader是自己定义的ClassLoader,同AppClassLoader类,不同的事,他限定了只加载一部分应用中的代码。
 
ClassLoader的双亲委派模型
 
     双亲委派模型,主要是整理java加载的秩序性,限定核心,扩展类的重复加载。
 
    BootStrap ClassLoader  —>  Extension ClassLoader  —> System ClassLoader —> Custom ClassLoader 的父子关系,是由组合关系组成的。加载类时,先请求parent加载器,如果加载成功就返回;否则自己再作加载。这样有个好处是核心jar类或者扩展jar类可以做到唯一性,不会每个ClassLoader都加载他。
 
 protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 查找class是否被加载
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                   // 先让父加载ClassLoader加载类
                    if (parent != null) { 
                        c = parent.loadClass(name, false);
                    } else {
                       // 启动类ClassLoader加载
                        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.
                    long t1 = System.nanoTime();
                    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;
        }
    }
 
从方法中,我们看到,ClassLoader先判断类有没有被加载,如果有直接返回;如果没有在请求父ClassLoader,父ClassLoader在递归相同的操作;如果父ClassLoader为null,表面为启动类加载器,换成启动类加载器加载;如果还没加载,在伦到自己加载。
 
从方法的修饰词 protected 可以看出,ClassLoader的双亲模式是不牢靠的,只要自定义的ClassLoader重载这个方法,就可能破坏双亲委派模型。
 

以上是关于ClassLoader心得的主要内容,如果未能解决你的问题,请参考以下文章

FLinkaccess closed classloader classloader.check-leaked-classloader

FlinkFlink classloader.check-leaked-classloader

ClassLoader

ClassLoader 详解及用途(写的不错)

classloader加载class的流程及自定义ClassLoader

ClassLoader工作机制