22 类加载器
1 类的唯一性、命名空间
何为类的唯一性
同一Class文件,被同一虚拟机的同一类加载器加载
命名空间
每个类加载器都有自己命名空间
同一命名空间,不会出现类的完整名字(包含类的包名)相同的两个类
不同的命名空间中,有可能会出现完整名字相同的两个类
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()方法
- 推荐方法
- 方式一:重写loadClass()方法
12 Java9新特性
JMOD 模块化
- 扩展机制被移除,扩展类加载器被保留,改名为平台类加载器PlatformClassLoader
- 平台类加载器、应用程序加载器,不再继承自java.net.URLClassLoader,而继承于BuiltinClassLoader
- 加载器有了名称,可以通过getName()方法获取。
- 类加载器双新委派机制变化
- 先判断归属某一模块,再判断该模块由哪个加载器加载