类加载机制之双亲委派模型

先说几个概念,方便后续理解:
1、java代码编译后会生成JVM能够识别的二进制字节流文件(*.class)。而JVM把Class文件中的类描述数据从文件加载到内存,并对数据进行校验、转换解析、初始化,使这些数据最终成为可以被JVM直接使用的Java类型,这个过程叫做JVM的类加载机制。

2、在JDK1.8以及之前,类加载器大概分为四个层级,依次为引导类加载器(Bootstrap ClassLoader)→拓展类加载器(Extension ClassLoader)→系统类加载器(Application ClassLoader)→用户自定义类加载器(Custom ClassLoader

3、不同类加载器负责加载的类也不同。这里大概说一下,Bootstrap ClassLoader它负责加载Java的核心类库,比如(%JAVA_HOME%/lib)目录下的rt.jar这样的核心类库;Extension ClassLoader负责加载扩展目录(%JAVA_HOME%/jre/lib/ext)下的jar包;APP ClassLoader负责加载CLASSPATH环境变量所指定的jar包与类路径。

4、 在JVM中的类加载过程,都是在类加载器的层次上,从下往上一层一层委托上去的,除非父类加载器加载不了(这里提一下,虽然我们都叫父类加载器,但是实际他们的关系并不是继承关系,而是代理关系),才会轮到本身来加载,这也就是为什么叫做双亲委派模型的原因了。(这里吐槽一下,为什么不是叫单亲呢,明明是一条链上去的

接着来看源码,可以更直观的了解类加载的流程。先看类加载器(ClassLoader)的声明:

public abstract class ClassLoader

可以看出一个公共抽象类。

然后接着看它加载类的方法(loadClass)实现:

 protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        // 1、先获取同步锁
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            // 2、检查该类是否已经被加载过
            Class c = findLoadedClass(name);
            // 3、若没被加载过
            if (c == null) {
                // 4、返回纳秒级的计数(与JVM固定的一个值计算得到?固定的值怎么取?话说这一步意义何在?)
                long t0 = System.nanoTime();
                try {
                    // 5、是否存在父类加载器
                    if (parent != null) {
                        // 6、采用父类加载器加载类
                        c = parent.loadClass(name, false);
                    } else {
                        // 7、该类是否被bootstrap加载器加载过,有则返回被加载生成的Class实例,没有则返回null
                        // 因为Bootstrap Classloader并不是由java代码实现的,不是一个java对象,所以当委托到拓展类类加载器再找它的父加载器时,虽然上面还有个Bootstrap ClassLoder,但是该加载器不能被Java代码访问到。所以我们可以查询某个类是否被引导类加载器加载过。
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }
                
                // 8、没成功加载出类?
                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    // 9、调用本身的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) {
                resolveClass(c);
            }
            return c;
        }
    }

再第9不调用了当前类的findClass方法,转到findClass:

protected Class<?> findClass(String name) throws ClassNotFoundException {
    throw new ClassNotFoundException(name);
}

这是一个抽象方法。实际是等着继承ClassLoader的子类,也就是平时我们自定义的类加载器去实现的。

猜你喜欢

转载自blog.csdn.net/insomsia/article/details/88532832