美文网首页
Java类加载源码阅读

Java类加载源码阅读

作者: 树生1995 | 来源:发表于2018-10-11 10:00 被阅读15次

    JVM自带加载器

    • 启动类加载器 BootStrap ClassLoader:最顶层的类加载器,负责加载 JAVA_HOME\lib 目录中的,或通过-Xbootclasspath参数指定路径中的,且被虚拟机认可(按文件名识别,如rt.jar)的类。可以通System.getProperty("sun.boot.class.path")查看加载的路径。
    • 扩展类加载器 Extention ClassLoader:主要加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件,或通过java.ext.dirs系统变量指定路径中的类库。也可以通过System.out.println(System.getProperty("java.ext.dirs"))查看加载类文件的路径。
    • 应用程序类加载器 Application ClassLoader:也叫做系统类加载器,可以通过getSystemClassLoader()获取,负责加载用户路径classpath上的类库。如果没有自定义类加载器,一般这个就是默认的类加载器。


    类加载层次关系

    类加载层次关系

    类加载器之间的这种层次关系叫做双亲委派模型。

    双亲委派模型要求除了顶层的启动类加载器(Bootstrap ClassLoader)外,其余的类加载器都应当有自己的父类加载器。这里的类加载器之间的父子关系一般不是以继承关系实现的,而是用组合实现的。

    • 下面看一段源码
    public class Launcher {
        private static Launcher launcher = new Launcher();
        private static String bootClassPath =
            System.getProperty("sun.boot.class.path");
    
        public static Launcher getLauncher() {
            return launcher;
        }
    
        private ClassLoader loader;
    
        public Launcher() {
            // Create the extension class loader
            ClassLoader extcl;
            try {
                extcl = ExtClassLoader.getExtClassLoader();
            } catch (IOException e) {
                throw new InternalError(
                    "Could not create extension class loader", e);
            }
    
            // Now create the class loader to use to launch the application
            try {
                loader = AppClassLoader.getAppClassLoader(extcl);
            } catch (IOException e) {
                throw new InternalError(
                    "Could not create application class loader", e);
            }
    
            Thread.currentThread().setContextClassLoader(loader);
        }
    
        /*
         * Returns the class loader used to launch the main application.
         */
        public ClassLoader getClassLoader() {
            return loader;
        }
        /*
         * The class loader used for loading installed extensions.
         */
        static class ExtClassLoader extends URLClassLoader {}
    
        /**
          * The class loader used for loading from java.class.path.
          * runs in a restricted security context.
          */
        static class AppClassLoader extends URLClassLoader {}
    

    从源码中我们看到
    (1)Launcher初始化的时候创建了ExtClassLoader以及AppClassLoader,并将ExtClassLoader实例传入到AppClassLoader中。
    (2)虽然上一段源码中没见到创建BoopStrap ClassLoader,但是程序一开始就执行了System.getProperty("sun.boot.class.path")

    附上Launcher相关文章:
    https://blog.csdn.net/jyxmust/article/details/72357372?utm_source=itdadao&utm_medium=referral

    • 类加载器中的继承关系
      AppClassLoader的父加载器为ExtClassLoaderExtClassLoader的父加载器为nullBoopStrap ClassLoader为顶级加载器。

    类加载机制-双亲委托

    当JVM加载Test.class类的时候

    • 首先会到自定义加载器中查找,看是否已经加载过,如果已经加载过,则返回该类。
    • 如果自定义加载器没有加载过,则询问上一层加载器(即AppClassLoader)是否已经加载过Test.class
    • 如果没有加载过,则询问上一层加载器(ExtClassLoader)是否已经加载过。
    • 如果没有加载过,则继续询问上一层加载(BoopStrap ClassLoader)是否已经加载过。
    • 如果BoopStrap ClassLoader没有加载过,则到自己指定类加载路径sun.boot.class.path下查看是否有Test.class字节码,有则加载并返回加载后的类c = findBootstrapClassOrNull(name)
    • 如果还是没找到调用c = findClass(name)到加载器ExtClassLoader指定的类加载路径java.ext.dirs下查找class文件,有则加载并返回类。
    • 依此类推,最后到自定义类加载器指定的路径还没有找到Test.class字节码,则抛出异常ClassNotFoundException

    这里注意
    每个自定义的类加载器都需要重写findClass方法,该方法的作用是到指定位置查找class文件并加载到JVM中,如果找不到则抛出ClassNotFoundException异常。

    类加载机制-双亲委托

    双亲委派模型最大的好处就是让Java类同其类加载器一起具备了一种带优先级的层次关系。这句话可能不好理解,我们举个例子。比如我们要加载顶层的Java类——java.lang.Object类,无论我们用哪个类加载器去加载Object类,这个加载请求最终都会委托给Bootstrap ClassLoader,这样就保证了所有加载器加载的Object类都是同一个类。

    双亲委派模型的实现比较简单,在java.lang.ClassLoaderloadClass方法中:

    protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
        {
            synchronized (getClassLoadingLock(name)) {
                // First, check if the class has already been loaded
                Class<?> c = findLoadedClass(name);
                if (c == null) {
                    long t0 = System.nanoTime();
                    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.
                        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;
            }
        }
    
    /**
         * Finds the class with the specified <a href="#name">binary name</a>.
         * This method should be overridden by class loader implementations that
         * follow the delegation model for loading classes, and will be invoked by
         * the {@link #loadClass <tt>loadClass</tt>} method after checking the
         * parent class loader for the requested class.  The default implementation
         * throws a <tt>ClassNotFoundException</tt>.
         *
         * @param  name
         *         The <a href="#name">binary name</a> of the class
         *
         * @return  The resulting <tt>Class</tt> object
         *
         * @throws  ClassNotFoundException
         *          If the class could not be found
         *
         * @since  1.2
         */
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            throw new ClassNotFoundException(name);
        }
    




    参考链接:

    https://www.jianshu.com/p/5f79217f2e18
    https://nomico271.github.io/2017/07/07/JVM%E7%B1%BB%E5%8A%A0%E8%BD%BD%E6%9C%BA%E5%88%B6/
    https://www.cnblogs.com/gdpuzxs/p/7044963.html

    相关文章

      网友评论

          本文标题:Java类加载源码阅读

          本文链接:https://www.haomeiwen.com/subject/ybwvaftx.html