类加载-双亲委派模型

0. 前言

尽管两个类来源于同一个 Class 文件,被同一个虚拟机加载,但是加载他们的类加载器不同时,那这两个类就不相等

1. 双亲委派模型

1.1 系统提供的3种类加载器

  • 启动类加载器(Bootstrap ClassLoader):加载 %JRE_HOME%\lib 目录下的类,例如 java.lang.*
  • 扩展类加载器(Extension ClassLoader):加载 %JRE_HOME%\lib\ext 目录下的类
  • 应用程序类加载器(Application ClassLoader):加载用户类路径(classpath)下的类

如果有需要的可以加入自定义类加载器

类加载器双亲委派模型

1.2 工作过程

一个类加载器收到类加载的请求时,会把这个请求委派给父类加载器,每个层次的类加载器都是如此,因此最终请求传送到启动类加载器,只有当父类加载器表示自己无法完成该类的加载(它的搜索范围中没有找到所需类),子加载器才会尝试自己加载

1.3 源码分析

// java.lang.ClassLoader
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.4 流程图

双亲委派流程图

1.5 作用

  • 避免类重复加载
  • 保证基础类在各环境中都是同一个类,避免自定义覆盖基础类时出现安全问题

2 破坏双亲委派模型

  • 涉及 SPI 的(JNDI、JDBC、JCE、JAXB、JBI 等)基本都是采用线程上下文件类加载器(Thread Context ClassLoader)加载,也就是父类加载器通过子类加载器完成类加载,破坏了双亲委派模型
  • 代码热替换(HotSwap)、模块热部署(Hot Deployment),例如 OSGI
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享