02详解字节码文件【下】-类加载器

类加载器(ClassLoader)是Java虚拟机提供给应用程序去实现获取类和接口字节码数据的技术。

类加载器只参与加载过程中的字节码获取并加载到内存这一部分。
类加载器的作用是什么?
类加载器(ClassLoader)负责在类加载过程中的字节码获取并加载到内存这一部分。通过加载字节码数据放入内存转换成byte[],接下来调用虚拟机底层方法将将byte[]转换成方法区和堆中的数据

1.类加载器的分类

1.1启动类加载器(重要)

        出于安全性考虑,无法让程序员在代码中去获取到启动类加载器。 在代码中获取到的为null,则为
启动类加载器。
通过启动类加载器去加载用户 jar 包:
1.放入jre/lib下进行扩展(不推荐)
2. 使用参数进行扩展(推荐,使用-Xbootclasspath/a:jar包目录/jar包名 进行扩展

1.2扩展类加载器(通用但不重要)

        扩展类加载器和应用程序类加载器, 它们的源码都位于sun.misc.Launcher中,是一个静态内部类。继承自URLClassLoader。具备通过目录 或者指定jar包将字节码文件加载到内存中
        默认加载Java安装目录/jre/lib/ext下的类文件。
通过扩展类加载器去加载用户 jar 包:
1.放入jre/lib下进行扩展(不推荐)
2. 使用参数进行扩展(推荐,使用-Djava.ext.dirs=jar包目录 进行扩展,这种方式会覆盖掉原始目录,可以用;(windows):(macos/linux)追加上原始目录

1.3应用程序类加载器

加载classpath下的类文件 我们项目中自己编写的类和 接口的文件,以及第三方jar 包(如maven依赖)中的类和接口的文件。

2.双亲委派机制

2.1父类加载器

每个Java实现的类加载器中保存了一个成员变量叫“父”(Parent)类加载器,可以理解为它的上级, 并不是继承关系。
应用程序类加载器的parent父类加载器是扩展类加载器,而扩展类加载器的parent是空。
启动类加载器使用C++编写,没有上级类加载器。
类加载器的继承关系可以通过classloader –t 查看

2.2双亲委派机制

双亲委派机制指的是: 自底向上查找是否加载过,再由顶向下进行加载( 向下委派加载起到了一个加载优先级的作用,从上至下优先级依次降低。
在类加载的过程中,每个类加载器都会先检查是否已经加载了该类,如果已经加载则直接返回,否则会 将加载请求委派给父类加载器
如果类加载的 parent null ,则会提交给启动类加载器处理。
如果所有的父类加载器都无法加载该类,则由当前类加载器自己尝试加载。所以看上去是自顶向下尝试加载。
第二次再去加载相同的类,仍然会向上进行委派,如果某个类加载器加载过就会直接返回

2.3三个问题

01.重复的类

如果一个类重复出现在三个类加载器的加载位置,应该由谁来加载?
答:启动类加载器加载,根据双亲委派机制,它的优先级是最高的

02.String类能覆盖吗

答:不能,会交由启动类加载器加载在rt.jar包中的 String类。 启动类加载器在检 查的时候就会返回 string类

03.类加载器的关系

应用类加载器的父类加载器是扩展 类加载器,扩展类加载器没有父类加载器,但是会委派给启动类加载器加载

2.4双亲委派机制有什么用

1.保证类加载的安全性
通过双亲委派机制,让顶层的类加载器去加载核心类,避免恶意代码 替换JDK中的核心类库,比如 java.lang.String,确保核心类库的完整性和安全性。
2.避免重复加载
双亲委派机制可以避免同一个类被多次加载,上层的类加载器如果加载过类,就会直接返回该类,避免重复加载。

3.打破双亲委派机制

3.1自定义类加载器

        Tomcat使用了自定义类加载器来实现应用之间类的隔离。每一个应用会有一个独立的类加载器加载对应的类
        自定义类加载器默认的父类加载器是应用程序类加载器Application
两个自定义类加载器加载相同限定名的类,不会冲突吗?
不会冲突 ,在同一个Java虚拟机中,只有 相同类加载器+相同的类限定名
会被认为是同一个类。
在Arthas中使用sc –d 类名的方式查看具体的情况。
        正确的去实现一个自定义类加载器的方式是重写 findClass 方法,这样不会破坏双亲委派机制

3.2线程上下文类加载器

JDBC中使用了DriverManager来管理项目中引入的不同数据库的驱动,比如mysql驱动、oracle驱动。
DriverManager类位于rt.jar包中,由启动类加载器加载
依赖中的mysql驱动对应的类,由应用程序类加载器来加载。
DriverManager属于rt.jar是启动类加载器加载的。而用户jar包中的驱动需要由应用类加载器加载,这就违反了双亲委派机制
DriverManage使用SPI机制,最终加载jar包中对应的驱动类
SPI中使用了线程上下文中保存的类加载器进行类的加载,这个类加载器一般是应用程序类加载器。
注意:
没有打破双亲委派机制
JDBC 只是在 DriverManager 加载完之后,通过初始化阶段触发了驱动类的加载,类的加载顺序依然遵循双亲委派机制

4.JDK9之后的类加载器

JDK9及之后扩展类加载器(Extension ClassLoader)变成了平台类加载器(Platform
ClassLoader)
  • 15
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值