Java的类加载器和双亲委派机制简单介绍

Java的双亲委派机制是从JDK1.2开始就引入的,在了解该机制之前先得知道Java的类加载器,
Java虚拟机中自带的几种类型类加载器:
启动(Bootstrap)类加载器:它负责将 <Java_Runtime_Home>/lib下面的类库加载到内存中(比如rt.jar)。开发者不可以直接使用该加载器。

标准扩展(Extension)类加载器:是由 Sun 的 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的。它负责将< Java_Runtime_Home >/lib/ext或者由系统变量 java.ext.dir指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器。

系统(System)类加载器:是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。它负责将系统类路径(CLASSPATH)中指定的类库加载到内存中。开发者可以直接使用系统类加载器。
线程上下文(Thread Context)类加载器:这个是个很特殊的东西,先看看官方的介绍,这里边的每一句话都需要好好理解。
Java 提供了很多服务提供者接口(Service Provider Interface,SPI),允许第三方为这些接口提供实现。常见的 SPI 有 JDBC、JCE、JNDI、JAXP 和 JBI 等。
这些 SPI 的接口由 Java 核心库来提供,而这些 SPI 的实现代码则是作为 Java 应用所依赖的 jar 包被包 含进类路径(CLASSPATH)里。SPI接口中的代码经常需要加载具体的实现类。
那么问题来了,SPI的接口是Java核心库的一部分,是由启动类加载器(Bootstrap Classloader)来加载的;SPI的实现类是由系统类加载器(System ClassLoader)来加载的。标准扩展(Extension)类加载器是无法找到 SPI 的实现类的,因为依照双亲委派模型,BootstrapClassloader无法委派系统(System)类加载器AppClassLoader来加载类。
在这里插入图片描述

**而线程上下文类加载器破坏了“双亲委派模型”,也就是父类加载器请求子类加载器去完成类加载的动作,可以在执行线程中抛弃双亲委派加载链模式,使程序可以逆向使用类加载器。**这个类加载器可以通过java.lang.Thread类的setContextClassLoaser()方法进行设置,如果创建线程时还未设置,它将会从父线程中继承一个,如果在应用程序的全局范围内都没有设置过的话,那这个类加载器默认就是应用程序类加载器。
使用jdbc时就是很常见的一个应用场景:

Class.forName("com.mysql.driver.Driver");
Connection conn = Driver.getConnection();
Statement st = conn.getStatement();

加载MySQL的驱动,其实就是调用父类加载器去处理

双亲委派模型具体的含义就是:某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载,上面的那个图就可以说明它们之间的关系。
自定义类加载器------ 》》 应用程序类加载器------ 》》 标准扩展类加载器 ------ 》》 启动类加载器
值得注意的是:各个类加载器之间是组合关系,并非继承关系,只是只是称为父类加载器,是便于理解。
简单介绍下,双亲其实是parents的翻译,其实就是咱们Java中经常说的父类的意思,只是翻译成了双亲,委派就是这个事情自己先不做,先找自己的父类去干,父类做了,自己就不用做了,父类处理不了,自己再尝试去处理。

那为什么有这个机制,这个机制的好处是什么呢?
当Java虚拟机要加载一个类时,这是肯定需要一个类加载器来加载,但是让那个加载器来处理合适呢,

Java里边是这样处理的,Java虚拟机的第一个类加载器是启动(Bootstrap)类加载器,这个加载器不是Java类,因此它不需要被别人加载,它嵌套在Java虚拟机内核里面,也就是JVM启动的时候Bootstrap就已经启动,它是用C++写的二进制代码(不是字节码),使用它可以去加载别的类。

首先当前线程的类加载器去加载线程中的第一个类(类A),如果类A中引用了类B,Java虚拟机将使用加载类A的类加载器去加载类B。如果类A和类B中有同一个类需要加载,比如java.lang.String。类A已经加载了一遍了,类B要加载时就会先递归的向父类加载器查找,如果已经加载过了,就不会再加载,如果找不到再向下,这样就能保证,不论多少个类都需要使用String,但类加载器只会加载一次,内存中有且仅有一份java.lang.String的字节码。

如果开发人员自定义一个java.lang.String的类,执行的时候,由于以上机制的存在,这个类当然也就不能正常加载,这也就保证了我们代码的安全性,要不然想想都可怕。

但作为一名高手,到底能不能实现这样的东西呢,自定义一个系统类,然后加载到内存里,我看有人说可以的,具体思路是:
自己定义一个类加载器,绕过双亲委派机制,这个类加载器也必须是特殊的。由于系统自带的三个类加载器都加载特定目录下的类,如果我们自己的类加载器放在一个特殊的目录,那么系统的加载器就无法加载,也就是最终还是由我们自己的加载器加载。这个方法我还没试过,欢迎大家下方评论区交流探讨。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值