22 类加载器

1 类的唯一性、命名空间

  1. 何为类的唯一性

    同一Class文件,被同一虚拟机的同一类加载器加载

  2. 命名空间

    每个类加载器都有自己命名空间

    同一命名空间,不会出现类的完整名字(包含类的包名)相同的两个类

    不同的命名空间中,有可能会出现完整名字相同的两个类

2 类加载机制的基本特征

  • 双亲委派模型,但不是所有类加载都遵守这个模型。
  • 可见性,子类加载器可以访问父类加载器
  • 单一性,由于父加载器的类型对子类加载器是可见的,父类加载的类,子类不允许再加载。

3 引导类加载器

启动类加载器(引导类加载器、Bootstrap ClassLoader)

  • 使用C/C++语言实现,嵌套在JVM内部
  • 用于加载Java核心库(lib/rt.jar sum.boot.class.path路径下内容
  • 出于安全考虑,Bootstrap启动类只加载包名为:java、javax、sun等开头的类
  • 加载扩展类和应用程序类加载器,并指定为他们的父类加载器

4 扩展类加载器

  • java语言编写,由sun.misc.Launcher$ExtClassLoader实现
  • 继承于ClassLoader类
  • 父类加载器为启动类加载器
  • 从java.ext.dirs系统属性所指向的目录中加载类库,或JDK安装目录jre/lib/ext子目录下加载类库

5 应用程序类加载器(系统类加载器,AppClassLoader)

  • java语言编写,由sun.misc.Launcher$AppClassLoader实现
  • 派生于ClassLoader类
  • 负责加载环境变量classpath或系统属性java.class.path指定路径下类库

6 用户自定义类加载器

7 获取不同的类加载器

  • 获得当前类的ClassLoader: clazz.getClassLoader()

  • 获得当前线程上下文的ClassLoader: Thread.currentThread().getContextClassLoader()

  • 获得系统的ClassLoader: ClassLoader.getSystemClassLoader()

8 双新委派

loadClass findClass

加载类时,层层向上获取类的信息,如果上层没有,判断是否符合当前加载器的加载规则,如果不符合,层层向下指派加载。

  • 优势
    • 避免类的重复加载,确保一个类的全局唯一性
    • 保护程序安全,防止核心API被随意篡改
      • 如:java.lang.String 只允许引导类加载器加载
  • 弊端
    • 检查类是否加载,是单向的,层层向上。上层类不知道下层的类加载。
  • 自定义类加载器
    • 可以不使用双亲委派模式
    • 不允许加载核心类,defineClass.preDefineClass 保护核心类库

9 破坏双亲委派机制

jdk1.2之前

双亲委派模型在JDK1.2之后才被引入

线程上下文类加载器

  • SPI
  • 线程上下文加载器

用户对程序动态性的追求: 代码热替换、模块热部署

10 沙箱安全机制

  • 作用:
    • 保证程序安全
    • 保护Java原生的JDK代码

11 自定义类加载器

  • 为什么要自定义类加载器

    • 隔离加载类
      • Web应用服务器,jar冲突
    • 修改类加载的方式
    • 扩展加载源
    • 防止源码泄漏
  • 注意

    • 不同类加载器的对象类型转换会发生异常
  • 实现

    • 方式一:重写loadClass()方法
      • 不推荐,避免打破双亲委派机制
    • 方式二:重写findClass()方法
      • 推荐方法

12 Java9新特性

JMOD 模块化

  1. 扩展机制被移除,扩展类加载器被保留,改名为平台类加载器PlatformClassLoader
  2. 平台类加载器、应用程序加载器,不再继承自java.net.URLClassLoader,而继承于BuiltinClassLoader
  3. 加载器有了名称,可以通过getName()方法获取。
  4. 类加载器双新委派机制变化
    • 先判断归属某一模块,再判断该模块由哪个加载器加载
上次更新:
贡献者: NOHI