JVM面试(四)类加载器和双亲委派机制

4 篇文章 0 订阅

什么是类加载器?

简单来说的话,是用于实现“类加载动作”的加载器
“通过一个类的全限定名来获取描述该类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需的类。实现这个动作的代码被称为“类加载器”(Class Loader)。

这里需要注意一个特点,对于任何一个类,都要根据这个类本身以及加载它的类加载器来共同确认其在Java虚拟机中的唯一性
有些拗口,但是希望各位同学能多念几遍理解一下。

从另一个角度来说,如果两类的名字相等,即使来自同一个.class文件,但是所用的类加载器不是同一个,虚拟机就不会认为是同一个类,是两个独立的类。

为什么需要双亲委派机制?

上面说了,不同类加载器加载出来的类,一定不相同。

所以,为了保护java底层本身的类不被篡改(比如java.lang.Object、java.lang.String)。
无论是在各种程序中,各种类加载器环境中都保证被同一个类加载器进行加载。
就是用双亲委派机制,全都委派给处于模型最顶端的启动类加载器进行加载。
如下图:
在这里插入图片描述

双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到最顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去完成加载。

其实代码也简单得很,如下:

protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{
	// 首先,检查请求的类是否已经被加载过了
	Class c = findLoadedClass(name);
	if (c == null) {
		try {
		if (parent != null) {
			c = parent.loadClass(name, false);
		} else {
			c = findBootstrapClassOrNull(name);
		}
		} catch (ClassNotFoundException e) {
			// 如果父类加载器抛出ClassNotFoundException
			// 说明父类加载器无法完成加载请求
		}
		if (c == null) {
			// 在父类加载器无法加载时
			// 再调用本身的findClass方法来进行类加载
			c = findClass(name);
		}
	}
	if (resolve) {
		resolveClass(c);
	}
	return c;
}

破坏双亲委派机制

很好理解啊,加载类的时候不按照这个顺序APPClassLoader->Ext ClassLoader->BootStrap ClassLoader进行加载就算是打破了双亲委派机制呗。

比如tomcat,只要用过tomcat部署工程的都知道,我们是把项目打成war包,让在webapp文件夹下面,那么就意味着tomcat同时可以运行多个web程序。

那在多个项目里面就有可能存在相同名称和路径的类。为了防止他们不冲突,tomcat就给每个web应用都创建一个类加载器实例,WebAppClassLoader。
该类重写了loaderClass()方法,优先加载当前应用目录下的类,如果找不到了,再进入用双亲委派机制一层层寻找加载器。
这其实算是一个双亲委派机制的补丁。

还有一种情况,双亲委派机制本身的模型就是“越基础的类,越由上层加载器来加载”。 那么什么是“基础”类? 就是哪些总作为被继承、调用API存在的类。 但是,如果存在那种,既有基础类型,又要回调用户代码怎么办?

这里最典型的就是JDBC,JDBC定义类接口,但是实现类肯定是由各个厂商来实现的, 比如mysql。
我们使用jdbc的时候,通过DriverManager来获取connection链接的,明显DriverManager是基础类,由BootstrapClassLoader加载的。

但是在我们使用DriverManager.getConnection()的时候,获取的一定是数据库厂商的类,BootstrapClassLoader不可能加载到第三方厂商的类啊。
解决方案就是,DriverManager在初始化的时候获取「线程上下文加载器」(Thread Context ClassLoader),在获取connection的时候使用线程上下文加载器来加载connection,这里的线程上下文加载器实际上还是App ClassLoader。
所以在获取connection的时候先找ExtClassLoader和BootstrapClassLoader加载器,只不过这俩加载器肯定加载不到,最终还是由AppClassLoader来加载。

其实话说回来,这些也可以算作双亲委派机制的加强补丁,并不是“破坏”双亲委派机制。 仁者见仁智者见智吧

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木小同

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值