Java class loader source code analysis

1. Source code implementation of class loader

Java class loading mechanism and object instantiation have clarified the types of class loaders in Java. Simply put, Java comes with three class loaders. Their specific functions areDynamically load the class file into the JVM virtual machine as needed. The corresponding implementations of these three class loaders are as follows:

  1. Boot class loader, Bootstrap ClassLoader
    loading system attribute sun.boot.class.pathclass in the specified path, it is written by the C / C ++, it is part of a virtual machine, which can not be achieved in the known java code
  2. Extend the class loader, Extension ClassLoader
    load java.ext.dirsthe class under the path specified by the system property , the implementation class issun.misc.Launcher.ExtClassLoader
  3. Application class loader, Application ClassLoader
    loading the environment variable ClassPathin the library, the system property is java.class.patha specified path, for the implementation classsun.misc.Launcher.AppClassLoader

Insert picture description here

1.1 Abstract class loader ClassLoader

java.lang.ClassLoader It is an abstraction of the class loader at the Java level. This class regulates the basic process of class loading. The more important properties and methods are as follows:

  1. parent: A reference to the parent class loader. A class loader usually saves a reference to the parent class loader to implement the parent delegation mechanism
  2. loadClass()Method, this method is the core method of the class loader, which implements the logic of parent delegation
public abstract class ClassLoader {
    
    
    // The parent class loader for delegation
    // Note: VM hardcoded the offset of this field, thus all new fields
    // must be added *after* it.
    private final ClassLoader parent;

    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;
        }
    }

1.2 ExtClassLoader

sun.misc.Launcher.ExtClassLoader It is the implementation class of the extended class loader. The more important methods of this class are as follows:

  1. getExtDirs()The method specifies the java.ext.dirsclass under the path specified by its loading system property
  2. Its construction method with parameters calls the construction method of the parent class, and the passed parent class loader parameter is explicitly specified as null, that is, the extended class loader does not have a Java-level parent class loader
static class ExtClassLoader extends URLClassLoader {
    
    
        private static volatile Launcher.ExtClassLoader instance;

        public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
    
    
            if (instance == null) {
    
    
                Class var0 = Launcher.ExtClassLoader.class;
                synchronized(Launcher.ExtClassLoader.class) {
    
    
                    if (instance == null) {
    
    
                        instance = createExtClassLoader();
                    }
                }
            }

            return instance;
        }

        private static Launcher.ExtClassLoader createExtClassLoader() throws IOException {
    
    
            try {
    
    
                return (Launcher.ExtClassLoader)AccessController.doPrivileged(new PrivilegedExceptionAction<Launcher.ExtClassLoader>() {
    
    
                    public Launcher.ExtClassLoader run() throws IOException {
    
    
                        File[] var1 = Launcher.ExtClassLoader.getExtDirs();
                        int var2 = var1.length;

                        for(int var3 = 0; var3 < var2; ++var3) {
    
    
                            MetaIndex.registerDirectory(var1[var3]);
                        }

                        return new Launcher.ExtClassLoader(var1);
                    }
                });
            } catch (PrivilegedActionException var1) {
    
    
                throw (IOException)var1.getException();
            }
        }

        void addExtURL(URL var1) {
    
    
            super.addURL(var1);
        }

        public ExtClassLoader(File[] var1) throws IOException {
    
    
            super(getExtURLs(var1), (ClassLoader)null, Launcher.factory);
            SharedSecrets.getJavaNetAccess().getURLClassPath(this).initLookupCache(this);
        }

        private static File[] getExtDirs() {
    
    
            String var0 = System.getProperty("java.ext.dirs");
            File[] var1;
            if (var0 != null) {
    
    
                StringTokenizer var2 = new StringTokenizer(var0, File.pathSeparator);
                int var3 = var2.countTokens();
                var1 = new File[var3];

                for(int var4 = 0; var4 < var3; ++var4) {
    
    
                    var1[var4] = new File(var2.nextToken());
                }
            } else {
    
    
                var1 = new File[0];
            }

            return var1;
        }
        
     ......
}

1.3 Application class loader AppClassLoader

Application class loader is also calledSystem class loader, sun.misc.Launcher.AppClassLoaderIs its implementation class, the more important methods of this class are as follows:

  1. getAppClassLoader()The method specifies the java.class.pathclass under the path specified by its loading system property
  2. Rewrite the loadClass()way to do an optimized loading class files, if a class exists in the cache directory but not in memory, directly carried out by 连接, or otherwise need to parent class loader to load
static class AppClassLoader extends URLClassLoader {
    
    
        final URLClassPath ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);

        public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
    
    
            final String var1 = System.getProperty("java.class.path");
            final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1);
            return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() {
    
    
                public Launcher.AppClassLoader run() {
    
    
                    URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2);
                    return new Launcher.AppClassLoader(var1x, var0);
                }
            });
        }

        AppClassLoader(URL[] var1, ClassLoader var2) {
    
    
            super(var1, var2, Launcher.factory);
            this.ucp.initLookupCache(this);
        }

        public Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException {
    
    
            int var3 = var1.lastIndexOf(46);
            if (var3 != -1) {
    
    
                SecurityManager var4 = System.getSecurityManager();
                if (var4 != null) {
    
    
                    var4.checkPackageAccess(var1.substring(0, var3));
                }
            }

            if (this.ucp.knownToNotExist(var1)) {
    
    
                Class var5 = this.findLoadedClass(var1);
                if (var5 != null) {
    
    
                    if (var2) {
    
    
                        this.resolveClass(var5);
                    }

                    return var5;
                } else {
    
    
                    throw new ClassNotFoundException(var1);
                }
            } else {
    
    
                return super.loadClass(var1, var2);
            }
        }
    ......
}

2. The realization of the parent delegation mechanism

Insert picture description here

The figure is a possible class loading process, many important steps in the process is nativethe method to achieve, can not know the details of the Java layer. The core method code of the Java layer loading class is as follows. In a brief description, it mainly includes the following steps:

  1. A AppClassLoadertime to load class, first see if the class has been loaded before, have acquired from the cache, or need to delegate to the parent class loader to handle
  2. ExtClassLoaderProcesses and AppClassLoaderfully consistent, if it had not loaded the target class, by Bootstrap ClassLoaderto perform load logic that is sun.mic.boot.classconfigured path to the target class is loaded, loaded returns, no load to let the child find their own loader
  3. Bootstrap ClassLoaderIf it is not successfully loaded into the target class, then you will find the target class to load ExtClassLoaderin the java.ext.dirsconfigured path, return if it succeeds, and then let the subloader load the class if it fails
  4. ExtClassLoaderLoad class unsuccessful, AppClassLoaderthe java.class.pathsearch target class of the path configuration, load returned to find it. If it is not found, let the subclass loader find it. If there is no subclass, various exceptions will be thrown.
 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); // 1.首先判断类是否已经被加载
            if (c == null) {
    
     // 2. 未被加载则进行双亲委派加载
                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) {
    
     //3.父类加载器 loadClass 未加载到类才调用 findClass
                    // 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;
        }
    }

Guess you like

Origin blog.csdn.net/weixin_45505313/article/details/106547155