前言
类加载机制:将一个类的.class文件的二进制字节流数据,读取到内存中,并且创建一个java.lang.Class对象,封装到元数据空间的数据存储结构
1. Class Loader分类
1.1 Bootstrap ClassLoader(根加载器)
1.2 Extension ClassLoader(扩展类加载器)
1.3 Application ClassLoader(系统类加载器)
我们平时写的代码都是由系统类加载器加载
1.4 自定义类加载器
继承ClassLoader
2.双亲委派机制
由来:
a.当一个类加载器收到类加载请求时,它不会先自己去加载,而是交由父类加载器去加载,传递到最上层的Bootstrap ClassLoader加载器无法加载该类时,再传递给子类加载器加载。
b.无法加载:类加载根据类的全限定名,在类负责的加载路径中找不到该类
c.上图中箭头指向并非继承关系,而是一种组合方式实现的逻辑关系
d.双亲委派的代码实现
双亲委派目的:为了保证核心类库的安全、防止篡改、保证类的唯一性
3.如何打破双亲委派机制
1.重写loadClass方法
问题:既然jvm推荐并且希望开发者遵循双亲委派机制,为什么不把loadClass方法设置为final方法,这样就可以有效防止重写loadClass方法
回答:双亲委派机制是jdk1.2提出的,但是java.lang.ClassLoader 的load class方法呢在java很早的版本就有了。引出双亲委派机制时,已经有很多重写loadClass这样的方法了,所有jvm只能采取向下兼容的方式。推荐用户去重写findClass()方法,而不是重写loadClass()方法。
2.SPI打破双亲委派机制
举例
jdk需要提供数据库的功能,但是只是提供了Driver接口,具体实现由数据库产商自己去实现。而jdk代码包中的代码是由BootStrap类加载器去加载,这时候如果由BootStrap类加载器去加载接口实现类,就会导致上层类加载器调用下层类加载器的情况,产生了双亲委派模型的破坏。
所以java为了解决这个问题提出了SPI机制,将META-INF/services/下文件的类委派给子类加载器去加载到JVM中
在DriverManager 类静态代码块中调用了loadInitialDrivers()方法
调用ServiceLoader.load(Driver.class)方法,由子类加载器加载META-INF/services/java.sql.Driver 文件里边的类到JVM内存
查看类加载器情况