JVM-2

命名空间的补充说明

  1. 关于命名空间的补充说明

    1. 子加载器所加载的类可以访问父加载器所加载的类
    2. 父加载器所加载的类无法访问子加载器所加载的类
    3. 在jvm中是可以存在多个命名空间的,每个命名空间之间是相互隔离开的。命名空间里面的类时相互不可见的。
    4. 在运行期,一个java类是由该类的完全限定名(binary name,二进制名)和用于加载该类的定义类加载器(defining loader)所共同决定的。如果同样的名字(即相同的完全限定名)的类是由两个不同的加载器所加载,那么这些类就是不同的,即便.class文件的字节码完全一样,并且从相同的位置加载亦如此。
  2. 类加载器双亲委托模型的好处

    1. 可以确保java核心库的类型安全:所有的java应用都至少会引用java.lang.Object类,也就是说在运行期 java.lang.Object这个类会被加载到java虚拟机中;如果这个加载过程是由java应用自己的类加载器所完成的,那么很可能就会在jvm中存在多个版本的java.lang.Object类,而且这些类之间还是不兼容的,相互不可见的(正是命名空间在发挥着作用)。 借助于双亲委托机制,java核心类库中的类的加载工作都是由启动类加载器统一来完成,从而确保了java应用所使用的都是同一个版本的java核心类库,他们之间都是相互兼容的。
    2. 可以确保java核心类库所提供的类不会被自定义的类所替代
    3. 不同的类加载器可以为相同名称(binary name)的类创建额外的命名空间。相同名称的类可以并存在java虚拟机中,只需要用不同的类加载器来加载他们即可,不同类加载器所加载的类之间是不兼容的。这就相当于在java虚拟机内部创建了一个又一个相互隔离的java类空间,这类技术在很多框架中都得到了实际应用
  3. 先有鸡还是先有蛋问题

    1. 我们知道对于加载器也是java类,那么加载器又是由谁来加载的?
    2. 内建于JVM的启动类加载器会加载java.lang.ClassLoader以及其他的java平台类。当JVM启动时,一块特殊的机器码会运行,他会加载扩展类加载器与系统类加载器 这块特殊的机器码就叫做启动类加载器(bootstrap)启动类加载器并不是java类,而其他的加载器则是java类。启动类加载器是特定于平台的机器指令,他负责开启整个加载过程。所有类加载器(除了启动类加载器)都被实现为java类,不过总归要有一个组件来加载第一个java类加载器,从而让整个加载过程能够顺利进行下去,加载第一个纯java类加载器就是启动类加载器的职责。启动类加载器还会负责加载供JRE,正常运行所需的基础组件,这包括java.util与java.lang包中的类等等
  4. 线程上下文类加载器分析和实现

    1. 线程上下文类加载器

      • 当前类加载器(Current Classloader) 用于加载当前类的类加载器
      • 每一个类都会使用自己的类加载器(即加载自身的类加载器)来加载其他类(指的是这个类所依赖的其他类)如果ClassX引用了ClassY,那么ClassX的类加载器就会去加载ClassY 前提的ClassY尚未被加载
      • 线程上下文类加载器是从JDK1.2开始引入的,类Thread中的getContextClassLoader()与setContextClassLoader(ClassLoader cl)分别用于获取和设置上下文类加载器。
      • 如果没有通过setContextClassLoader(ClassLoader cl)进行设置的话,线程将继承其父线程的上下文类加载器。java应用运行时的初始线程的上下文类加载器,在线程中运行的代码可以通过该类加载器来加载该类与资源。
    2. 线程上下文类加载器的重要性

      • SPI(Service Provider Interface)服务提供者接口 面临父加载器看不到子加载器的类的问题父ClassLoader可以使用当前线程Thread.currentThread().getContextLoader()所指定的classloader加载的类这就改变了父ClassLoader不能使用子ClassLoader或是其他没有直接父子关系的ClassLoader加载的类的情况,即改变了双亲委托模型。
      • 线程上下文类加载器就是当前线程的Current Classloader
      • 在双亲委托模型下,类加载时由下至上的,即下层的类加载器会委托上层进行加载,但是对于SPI来说,有些接口是由java核心库说提供的,而java核心库是由启动类加载器来加载的,而这些接口的实现却来自于不同的jar包(厂商提供),java启动类加载器是不会加载其他来源的jar包,这样传统的双亲委托模型就无法满足SPI的要求,而通过给当前线程设置上下类加载器,就可以由设置的上下文类加载器来实现对于接口实现类的加载。
    3. 线程上下类类加载的一般使用模式(获取 - 使用 - 还原)

      1. 伪代码:

        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            try {
                // targetTccl 你准备使用的类加载器
                Thread.currentThread().setContextClassLoader(targetTccl);
                // myMethod里面则调用Thread.currentThread().getContextClassLoader(),获取当前线程的上下文类加载器做某些事情
                myMethod();
            } finally {
                Thread.currentThread().setContextClassLoader(classLoader);
            }
            // 如果一个类由类加载器A加载,那么这个类的依赖类也是由相同的类加载器加载的(如果该依赖类之前没有被加载过的话)
            // ContextClassLoader的作用就是为了破坏java的类加载的委托机制
            // 当高层提供了统一的接口让低层去实现,同时又要在高层加载(或实例化)低层的类时,就必须要通过现场上下文类加载器来帮助高层的ClassLoader找到并加载该类
        
        
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 作者:成 富, 软件工程师, IBM 中国软件开发中心 类加载器(class loader)是 Java™中的一个...
    Android技术研究阅读 9,301评论 0 74
  • ClassLoader翻译过来就是类加载器,普通的java开发者其实用到的不多,但对于某些框架开发者来说却非常常见...
    时待吾阅读 4,748评论 0 1
  • 类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一。它使得 Java 类可以被动态加载到...
    CHSmile阅读 5,492评论 0 12
  • 0、前言 读完本文,你将了解到: 一、为什么说Jabalpur语言是跨平台的 二、Java虚拟机启动、加载类过程分...
    vivi_wong阅读 5,045评论 0 10
  • 内容概述 “线程上下文类加载器”介绍 SPI(Service Provider Interface)探索 通过JD...
    tomas家的小拨浪鼓阅读 10,797评论 0 3