java源码解读之ClassLoader(loadClass方法)

8 篇文章 0 订阅
6 篇文章 0 订阅

本篇文章仅仅只是对ClassLoader类的loadClass方法从源码上进行分析,至于跟类加载相关的双亲委托模式等其他知识点,不做介绍与阐述,因为网上大把介绍这些的文章,而且我不认为自己能写得比他们好

接下来又是跟之前的两篇一样,直接贴相关的源代码啦~\(≧▽≦)/~

public abstract class ClassLoader {

    private static native void registerNatives();
    static {
        registerNatives();
    }

    private final ClassLoader parent;

    /**
     * ClassLoader类中的静态内部类,他可以决定指定的类是否具备并行的能力,
     * 若具备并行能力则ClassLoader下面的parallelLockMap便会被初始化,
     * 该静态内部类在ClassLoader被加载的时候便被初始化了
     */
    private static class ParallelLoaders {
        private ParallelLoaders() {}

        //存放具备并行能力的加载器类型的Set集合
        private static final Set<Class<? extends ClassLoader>> loaderTypes =
            Collections.newSetFromMap(
                new WeakHashMap<Class<? extends ClassLoader>, Boolean>());
        static {
            synchronized (loaderTypes) { loaderTypes.add(ClassLoader.class); }
        }

        /**
         * 将指定的类加载器注册成为一个具备并行能力的类加载器,注册成功则返回true,否则返回false
         */
        static boolean register(Class<? extends ClassLoader> c) {
            synchronized (loaderTypes) {
            	//只有当该类加载器的父类具备并行能力时,该类加载器方可成功注册
                if (loaderTypes.contains(c.getSuperclass())) {
                    loaderTypes.add(c);
                    return true;
                } else {
                    return false;
                }
            }
        }

        /**
         * 判断指定的classloader类加载器是否具备并行的能力
         */
        static boolean isRegistered(Class<? extends ClassLoader> c) {
            synchronized (loaderTypes) {
                return loaderTypes.contains(c);
            }
        }
    }

    //若当前类加载器具备并行能力,则该属性会被初始化
    private final ConcurrentHashMap<String, Object> parallelLockMap;
    /**
     * ClassLoader类的构造函数,在这里主要确定该类加载器是
     * 否具备并行能力与其他变量的初始化操作
     * @param unused
     * @param parent
     */
    private ClassLoader(Void unused, ClassLoader parent) {
        this.parent = parent;
        //若该类加载器具备并行能力(如何判断见ClassLoader类中的静态内部类)
        if (ParallelLoaders.isRegistered(this.getClass())) {
        	//初始化parallelLockMap
            parallelLockMap = new ConcurrentHashMap<>();
            package2certs = new ConcurrentHashMap<>();
            domains =
                Collections.synchronizedSet(new HashSet<ProtectionDomain>());
            assertionLock = new Object();
        } else {
            //不具备并行能力,parallelLockMap置为null
            parallelLockMap = null;
            package2certs = new Hashtable<>();
            domains = new HashSet<>();
            assertionLock = this;
        }
    }

    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }

    /**
     * 使用指定的二进制名称来加载类,这个方法的默认实现按照以下顺序查找类:调用findLoadedClass(String)方法
     * 检查这个类是否被加载过,使用父加载器调用loadClass(String)方法,如果父加载器为Null,类加载器装载虚拟机
     * 内置的加载器调用findClass(String)方法装载类,如果按照以上的步骤成功的找到对应的类,并且该方法接收的resolve
     * 参数的值为true,那么就调用resolveClass(Class)方法来处理类,ClassLoader的子类最好覆盖findClass(String)而不是
     * 这个方法,除非被重写,这个方法默认在整个装载过程中都是同步的(线程安全的)
     */
    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
    	//这里根据当前类加载器是否具备并行能力而获取对应的锁对象
        synchronized (getClassLoadingLock(name)) {
            /**
             * 在加载类之前先调用findLoadClass方法查找看该类是否加载过,
             * 若被加载过则直接返回该对象,无需二次加载,未加载过则返回null,
             * 进行下一个流程
             * PS:ClassLoader类中的findLoaderClass方法是一个本地方法,
             * 自定义的类加载器需要重写该方法
             */
            Class c = findLoadedClass(name);
            //若该类未被加载过
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                	//如果父类加载器不为空,则调用父类加载器的loadClass方法加载
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                    	//若父类加载器为空,则调用虚拟机的加载器Bootstrap ClassLoader来加载类
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {}
                //若以上的操作都没有成功加载到类
                if (c == null) {
                    long t1 = System.nanoTime();
                    //则调用该类自己的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) {
            	//这个方法用来给ClassLoader链接一个类(具体干嘛我不知道额)
                resolveClass(c);
            }
            return c;
        }
    }

    /**
     * 这个方法是根据当前类加载器是否具备并行能力而决定是否返回锁对象,
     * 当该类加载器不具备并行能力,则无需返回一个加锁对象,若具备并行能
     * 力,则返回一个新的加锁对象
     */
    protected Object getClassLoadingLock(String className) {
        Object lock = this;
        //根据parallelLockMap是否被初始化来判断当前类加载器是否具备并行能力
        if (parallelLockMap != null) {
        	//若该类加载器具备并行能力,则创建新的锁对象返回
            Object newLock = new Object();
            lock = parallelLockMap.putIfAbsent(className, newLock);
            if (lock == null) {
                lock = newLock;
            }
        }
        return lock;
    }
}
这里推荐自己觉得挺不错的一篇介绍类加载原理的博文http://blog.csdn.net/xyang81/article/details/7292380

完毕了额~~~铭记初衷,倾己所有微笑

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值