JVM类加载器(重点双亲委派模型)

版权声明:转载标明来源! https://blog.csdn.net/qq_39213969/article/details/88855637

一,类加载器

1.类加载器的定义:把列加载器阶段“通过一个类的全限定名来获取描述此类的二进制字节流” 这个动作放到java虚拟机外部去实现,以便让应用程序自己决定去如何获取所需要的类,实现这个动作的代码模块成为“类加载器”

2,类加载器应用于:类层次划分,OSGI,热部署,代码加密等领域。
3,类与类加载器:两个类相等的条件:加载他的类加载器,这个类本身,两者一同确定了该类在java虚拟机中的唯一性;(每一个类加载器都有独立的类名称空间)
4.一个类来自应用程序的类加载器加载,另一个类时有我们自定义的类加载器来加载的,虽然来自同一个class文件,但他们依然是两个独立的类。通过对象所属鱼的类的实例时发现他们不来自一个类。

二,三个加载器

1.在java虚拟机看来,只有两种类加载器;

(1)启动类加载器(这个类加载器使用C++实现,是虚拟机的一部分);
(2)所有其他类的加载器(这些类的加载器都是拿java语言实现的,独立于虚拟机外部,并且全部继承于抽象类java.lang.ClassLoader)。

2.java程序使用的类加载器(我们的程序都是由一下三个加载器配合进行加载的,如果有必要还可以使用自己自定义的加载器)

(1)启动类加载器 :负责加载存放在java_home\lib文件夹里并且能被java虚拟机识别的类库加载到虚拟机内存中。
启动类加载器不能被java程序直接引用,用户在编写自定义类加载时,如果需要把请求委派给启动类加载器,那就直接用null代替即可。

(2)扩展类加载器:这个加载器加载java_home\lib\ext目录中的,开发者可以直接使用扩展类加载器。

(3)应用程序类加载起:由于这个加载器是ClassLoader中getsystemclassloader()方法的返回值,因此称为系统类加载器,他负责加载classpath】路劲上所制定的类库,开发者可以直接使用这个类加载器(如果应用程序没有自定义的类加载器,那就默认使用应用程序类加载器(也就是系统类加载器))

三,双亲委派模型(## 非强制性的约束模型

在这里插入图片描述
1.双亲委派模型要求:除了顶层的启动类加载器之外,其余的类加载器必须要有自己的父类加载器。(它是一种java设计者推荐给java开发者的类加载器实现方式)
注意:这里类加载器之间的关系不会以继承的关系来实现,而是都使用组成关系来复用父加载器的代码。

2,双亲委派模型的工作过程

(1)一个类加载器收到类加载请求,首先不尝试加载这个类,而是把这个请求委派给父类加载器去完成。
(2)因此所有的类加载秦秋最终都会到达顶层的启动类加载器中。
(3)只有当父类加载器反馈自己无法完成这个类的加载请求时,子加载器才会尝试自己去加载。

3.双亲委派模型对java程序的稳定运行很重要,实现它的代码放在java.lang.ClassLoader的loadclass()方法中。
代码执行过程:先检查是否已经被加载过,若没有被加载过则调用父类加载器的loadClass()方法,若父类加载器为空则默认使用类加载器作为父加载器。如果父类加载器加载失败,则抛出异常然后在使用自己findclass()方法进行分加载类。

四,破坏双亲委派模型(三次危机)

1.loadClass()方法与findClass()方法(解决方法就是双亲委派模型)。

2.模型自身的缺陷,基础类调用回用户的代码,无法识别。(JNDI服务,涉及SPI(代码)的加载动作)
解决方法:线程上下文类加载器,这个类加载器可以通过java.lang.Thread类的setcontextclassloader()方法进行设置。(未创建则继承父线程,若果从来没有设置过则默认的类加载器就是应用程序加载器)
注意:这是舞弊的方法,这样子实际上就是打通了双亲委派模型的层次结构来逆向使用类加载器(实际上已经违背了双亲委派的一般性委派原则,但是也是无可奈何的)。
3.只要涉及SPI加载的动作都是遵循这种线程上下文类加载器的方式(JNDI,JDBC,JCE等)
4.第三次破坏:由用户对程序动态性的追求所导致的。(动态性是指:代码热替换,模块热部署)
**说白:**希望更换应用程序就像换键盘换鼠标一下不需要重启机器就可以完成部署。这对于生产系统比较受欢迎。
5.java模块化标准:OSGi(其实现模块化热部署)关键是:它自定义的类加载机制的出现。
注意:每一个程序模块(OSGi中称为Bundle)都有一个自己的类加载器,更换程序模块时,就把模块连同类加载器一起换掉以实现代码的热替换。

6.OSGi模式下,类加载器不再是简单的双亲委派模型中的树形结构了,而是进一步发展为更加复杂的网状结构

7.当收到类加载请求时,OSGi将按照以下顺序进行类搜索:

*(1)将以java.开头的类委派给父类加载器加载
(2)否则,将委派列表名单内的类委派给父类加载器加载。
(3)将Import中的类委派给Export这个类的bundle的类加载器加载。
(4)查找当前Bundle的ClassPath,使用自己的类加载器加载。
(5)查找类是否在Fragment Bundle中,如果在就委派给Fragment Bundle的类加载器加载。
(6)查找类是否在Dynamic Import中,如果在就委派给Dynamic Import的类加载器加载。
(7)否则,类查找失败。

注意:该模块化下,只有(1)(2)点遵循双亲委派原则,其他的类查找都是在平级的类加载器中进行的。(莫种意义上破坏也是一种创新,想OSGi一样何尝不是一种创新)。

掌握OSGi的实现,就可说算是掌握类加载器的精髓了!!!

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_39213969/article/details/88855637