ClassLoader源码分析

446 阅读2分钟

主要分析类加载类的方法loadClass

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); //native-查找类是否已经被加载了
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name); //native-使用启动类加载器加载
                    }
                } 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;
        }
    }

通过类全限定名查找是否已经加载了,如果还未加载,则使用父类加载器或者启动类加载器加载该类,如果仍然未加载到,则使用当前类加载器加载

类加载器是否有并发能力

getClassLoadingLock

获取一个对象作为锁,如果parallelLockMap为空,则表明loadClass中加锁的对象是当前类实例;否则表明加锁的对象是Object,且对于同一个className会获取到同样的Object对象

    protected Object getClassLoadingLock(String className) {
        Object lock = this;
        if (parallelLockMap != null) {
            Object newLock = new Object();
            lock = parallelLockMap.putIfAbsent(className, newLock);
            if (lock == null) {
                lock = newLock;
            }
        }
        return lock;
    }

基于parallelLockMap对象,key是className,value是Object对象

 private final ConcurrentHashMap<String, Object> parallelLockMap;

构造器

那么,parallelLockMap是哪里初始化的?

构造器初始化了的时候,但是受到isRegistered方法的控制

 private ClassLoader(Void unused, ClassLoader parent) {
        this.parent = parent;
        if (ParallelLoaders.isRegistered(this.getClass())) {
            parallelLockMap = new ConcurrentHashMap<>();
            package2certs = new ConcurrentHashMap<>();
            domains =
                Collections.synchronizedSet(new HashSet<ProtectionDomain>());
            assertionLock = new Object();
        } else {
            // no finer-grained lock; lock on the classloader instance
            parallelLockMap = null;
            package2certs = new Hashtable<>();
            domains = new HashSet<>();
            assertionLock = this;
        }
    }

ParallelLoaders

该类是ClassLoader的内部静态类,用于实现当前的加载器被定位为具有并行能力,通过Set保存着类加载器实例,在set中的类加载器是具备并行能力的。结合getClassLoadingLocK。

private static class ParallelLoaders {
        private ParallelLoaders() {}

        // the set of parallel capable loader types
        //保存类加载器实例
        private static final Set<Class<? extends ClassLoader>> loaderTypes =
            Collections.newSetFromMap(
                new WeakHashMap<Class<? extends ClassLoader>, Boolean>());
        static {
            synchronized (loaderTypes) { loaderTypes.add(ClassLoader.class); }
        }

        /**
         * Registers the given class loader type as parallel capabale.
         * Returns {@code true} is successfully registered; {@code false} if
         * loader's super class is not registered.
         */
        //把类加载器实例存入set
        static boolean register(Class<? extends ClassLoader> c) {
            synchronized (loaderTypes) {
                if (loaderTypes.contains(c.getSuperclass())) {
                    loaderTypes.add(c);
                    return true;
                } else {
                    return false;
                }
            }
        }

        /**
         * Returns {@code true} if the given class loader type is
         * registered as parallel capable.
         */
        //判断set是否有指定类加载器
        static boolean isRegistered(Class<? extends ClassLoader> c) {
            synchronized (loaderTypes) {
                return loaderTypes.contains(c);
            }
        }
    }

综上所述,在ParallelLoaders set中的类加载器是具备并行能力的,否则不具备。

注册

那么set中值怎么放进去的呢?

注册方法

在ClassLoader类中

@CallerSensitive
    protected static boolean registerAsParallelCapable() {
        Class<? extends ClassLoader> callerClass =         //获取当前类加载器
            Reflection.getCallerClass().asSubclass(ClassLoader.class);
        return ParallelLoaders.register(callerClass);      //注册到set中
    }

URLClassLoader

在该类中有静态代码块,调用了上述注册方法

static {
        sun.misc.SharedSecrets.setJavaNetAccess (
            new sun.misc.JavaNetAccess() {
                public URLClassPath getURLClassPath (URLClassLoader u) {
                    return u.ucp;
                }
            }
        );
        ClassLoader.registerAsParallelCapable();
    }

以下这两个类加载器继承了URLClassLoader,因此,在使用这两个类加载器的时候也就具备上述注册的功能。其它类加载器类似。

扩展类加载器

 static class ExtClassLoader extends URLClassLoader {
       //...
 }

应用程序类加载器

 static class AppClassLoader extends URLClassLoader {
       //...
 }

全文倒序写,适合从下往上阅读。