类加载器 -双亲委派模式

我们首先了解了类的加载过程,主要有5个阶段:
加载—验证—准备—解析—初始化。

那么什么是类加载器呢?
类加载器首先我们写好的 .java文件经过编译后会形成 .class字节码文件,然后类加载器将.class文件加载为class模板,并可以通过new关键字创建实例对象,实例对象可以通过getClass方法获取class模板,class模板可以通过getClassLoader方法获取类加载器。

在这里插入图片描述

类加载器:
主要有四种:启动类加载器、扩展类加载、应用程序类加载器、自定义类加载器

这四类类加载的关系为:

在这里插入图片描述
当加载一个对象的时候,会从应用程序类加载器往上一层层找,找到扩展类加载器,然后再往上找,找到根加载器,如果根加载器无法加载,那么就会看看扩展类加载器是否可以加载,如果也不可以,那么就去看应用程序类加载器是否能够加载,如果不能的话,则就会报错。

这个过程就是双亲委派机制。

深入理解Java虚拟机中这样定义它的工作流程的:
在这里插入图片描述
使用双亲委派模型的优点:
在这里插入图片描述
缺陷:
无法满足灵活的类加载方式。

解决方案:
自己重写一些方法来破坏双亲委派模型。

SPI机制
一个典型的例子便是JNDI服务。JNDI存在的目的就是对资源进行查找和集中管理,它需要调用由其他厂商实现并部署在应用程序的ClassPath下的JNDI服务提供者接口(Service Provider Interface,SPI)的代码,现在问题来了,启动类加载器是绝不可能认识、加载这些代码的,那该怎么办?

解决方案:线程上下文类加载器(Thread Context ClassLoader)

JNDI服务使用这个线程上下文类加载器去加载所需的SPI服务代码,这是一种父类加载器去请求子类加载器完成类加载的行为,这种行为实际上是打通了双亲委派模型的层次结构来逆向使用类加载器,已经违背了双亲委派模型的一般性原则,但也是无可奈何的事情。Java中涉及SPI的加载基本上都采用这种方式来完成,例如JNDI、JDBC、JCE、JAXB和JBI等。不过,当SPI的服务提供者多于一个的时候,代码就只能根据具体提供者的类型来硬编码判断,为了消除这种极不优雅的实现方式,在JDK 6时,JDK提供了java.util.ServiceLoader类,以META-INF/services
中的配置信息,辅以责任链模式,这才算是给SPI的加载提供了一种相对合理的解决方案。

猜你喜欢

转载自blog.csdn.net/m0_46551861/article/details/115217163