1、JVM预定义加载器
(1) 启动(Bootstrap)类加载器:引导类装入器是用本地代码实现的类装入器。加载 <Java_Runtime_Home>/lib下面的核心类库或-Xbootclasspath选项指定的jar包加载到内存中。
(2) 扩展(Extension)类加载器:扩展类加载器是由Sun的ExtClassLoader(sun.misc.Launcher
E
x
t
C
l
a
s
s
L
o
a
d
e
r
)
实
现
的
。
它
负
责
将
<
J
a
v
a
R
u
n
t
i
m
e
H
o
m
e
>
/
l
i
b
/
e
x
t
或
者
由
系
统
变
量
−
D
j
a
v
a
.
e
x
t
.
d
i
r
指
定
位
置
中
的
类
库
加
载
到
内
存
中
。
(
3
)
系
统
(
S
y
s
t
e
m
)
类
加
载
器
:
系
统
类
加
载
器
是
由
S
u
n
的
A
p
p
C
l
a
s
s
L
o
a
d
e
r
(
s
u
n
.
m
i
s
c
.
L
a
u
n
c
h
e
r
ExtClassLoader)实现的。它负责将< Java_Runtime_Home >/lib/ext或者由系统变量-Djava.ext.dir指定位置中的类库加载到内存中。 (3) 系统(System)类加载器:系统类加载器是由 Sun的 AppClassLoader(sun.misc.Launcher
ExtClassLoader)实现的。它负责将<JavaRuntimeHome>/lib/ext或者由系统变量−Djava.ext.dir指定位置中的类库加载到内存中。(3)系统(System)类加载器:系统类加载器是由Sun的AppClassLoader(sun.misc.LauncherAppClassLoader)实现的。它负责将系统类路径java -classpath或-Djava.class.path变量所指的目录下的类库加载到内存中。
2、双亲委派模型
(1) 在JVM类加载中,使用的是双亲委派模型,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
(2) 类加载器间的相互关系
3、自定义加载器的工作流程
(1) 首先检查请求的类型是否已经被这个类装载器装载到命名空间中了,如果已经装载,直接返回;否则转入步骤2;
(2) 派类加载请求给父类加载器(更准确的说应该是双亲类加载器,真实虚拟机中各种类加载器最终会呈现树状结构),如果父类加载器能够完成,则返回父类加载器加载的Class实例;否则转入步骤3;
(3) 调用本类加载器的findClass(…)方法,试图获取对应的字节码,如果获取的到,则调用defineClass(…)导入类型到方法区;如果获取不到对应的字节码或者其他原因失败,返回异常给loadClass(…), loadClass(…)转而抛异常,终止加载过程
4、类加载器原理说明
(1)在JVM中不同类加载器加载同一个类得到的实例不相同,JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识,不同类加载器加载的类将被置于不同的命名空间。
(2)在Java虚拟机判断两个类是否相同的时候,使用的是类的定义加载器。也就是说,哪个类加载器启动类的加载过程并不重要,重要的是最终定义这个类的加载器。两种类加载器的关联之处在于:一个类的定义加载器是它引用的其它类的初始加载器。
(3)方法 loadClass()抛出的是 java.lang.ClassNotFoundException异常;方法 defineClass()抛出的是 java.lang.NoClassDefFoundError异常。
(4)类加载器在成功加载某个类之后,会把得到的 java.lang.Class类的实例缓存起来。下次再请求加载该类的时候,类加载器会直接使用缓存的类的实例,而不会尝试再次加载。也就是说,对于一个类加载器实例来说,相同全名的类只加载一次,即 loadClass方法不会被重复调用。
5、线程上下文加载器
我们可以通过java.lang.Thread类中的getContextClassLoader()和 setContextClassLoader(ClassLoader cl)方法来获取和设置线程的上下文类加载器。初始线程的上下文类加载器是系统类加载器(AppClassLoader),在线程中运行的代码可以通过此类加载器来加载类和资源。jdbc加载示意图:
很明显了确实通过线程上下文类加载器加载的,实际上核心包的SPI类对外部实现类的加载都是基于线程上下文类加载器执行的,通过这种方式实现了Java核心代码内部去调用外部实现类。
通过getSystemClassLoader()获取类加载器来加载classpath路径下的类具有代码部署到不同服务时会出现问题,因为这些服务使用的线程上下文类加载器并非AppClassLoader。
JAVA类加载原理解析
最新推荐文章于 2021-03-01 15:26:17 发布