类加载过程:
简洁来说就是将我们的已经完成编译的class字节码文件通过类加载器到我们JVM的内存运行时数据区成为我们可以在程序中可以使用的class对象,而类加载器就是通过双亲委派机制来实现的,这个也是反射的底层实现的原因
具体流程: 加载 链接 初始化
加载: 就是通过类加载器以及实现的双亲委派机制加载到JVM内存的运行时数据区
链接:这个过程里面分为验证 准备 解析
验证: 来确定这个类是否符合JVM的一些规范就是一个安全性的考虑
准备:对类里面的静态变量完成初始化 如里面的String类型的赋值为null int赋值为0等等
解析:就是对类中的修饰符进行一个解析的过程
初始化: 实现类中静态变量实现一个真正的赋值简洁来说根据实际的赋值来进行赋值
类加载器的类别:
1.根类加载器(BootStrap ClassLoader), 主要负责加载jre/lib/rt.jar相关的字节码文件的。
2.扩展类加载器(Extension ClassLoader), 主要负载加载 jre/lib/ext/*.jar 这些jar包的。
3.应用程序类加载器(Application ClassLoader), 主要负责加载用户自定义的类以及classpath环境变量所配置的jar包的。
4.自定义类加载器(UserClassLoader), 负责加载程序员指定的特殊目录下的字节码文件的。大多数情况下,自定义类加载器只需要继承ClassLoader这个抽象类,重写findClass()和loadClass()两个方法即可。
这三个类加载器是通过parent属性进行关系的联络的,但是根类记载器由于是C++来进行的所以为null
双亲委派机制:
就是当类加载器接受到类加载请求的时候不是自己进行加载而是会向上进行一个委派(也就是让父类加载器进行加载),然后以此进行类推直到根类加载器,然后根类记载器进行尝试加载如果能加载成功的话那么就直接进行加载,如果加载失败的话那么就让其的子类记载器进行加载如果没有自定义类加载器的话那么就应用程序类加载器进行加载
优点: 1.保护Java中的核心API 2.实现避免类的重复加载
破坏双亲委派机制:
原因(缺点):双亲委派机制具有一定的局限性,如果一个类在一个类加载器里面进行加载过之后那么就会使得如果出现相同的全限类名的类的话那么就会在这个类加载器都会进进行加载
案例:
1.Tomcat:
问题:
Tomcat可以启动多个web应用程序那么这个里面就会出现全限类名相同的类.这个就会导致不同的web应用程序使用的类加载器是同一个类加载器,但是不同的web应用程序其使用的第三方类库的版本号如 mysql,spring等等版本不一致那么就会造成一个版本冲突的问题
解决方案:
Tomcat就为每一个web应用程序自定义一个类加载器(Web类加载器),然后由自定义的类加载器进行类的加载
2.JDBC:
JDBC中DriveMange类的class位于根加载器,那么进行加载的时候就会使用根类加载器进行一个加载
问题:
但是通过下图可以看出这个是要加载所有实现Drive接口类但是这些类都是位于classPath路径下面的如果是遵循双亲委派机制的是不可能实现的
解决方案:
通过线程上下文类加载器(默认是应用程序性类加载器)进行类的加载破坏双亲委派
我们深入到ServiceLoader.load方法就可以看到:
public static <S> ServiceLoader<S> load(Class<S> service) {
//获取线程上下文类加载器
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
标签:委派,自定义,应用程序,双亲,加载,进行
From: https://blog.csdn.net/2201_75397629/article/details/142991914