类加载器和双亲委托机制

4 篇文章 0 订阅

类加载器的作用

类加载器将字节码文件加载到内存当中,同时在方法区中生成对应的java.lang.Class对象,作为外部访问方法区的入口。所有的java类都需要经过类加载器的加载才能加载到内存中,那么Java中的类加载器究竟什么呢?

类加载器的层次结构

JavaSE中类加载器分为引导类加载器(Bootstrap ClassLoader),扩展类加载器(Extensions ClassLoader),系统类加载器(也称为应用程序类加载器Application ClassLoader),自定义的类加载器。

它们具有如下的层次关系:

除了引导类加载器,其他几个类加载器都是通过继承抽象类ClassLoader类实现的,而且这些类具有父子关系,但不是通过继承实现的父子关系(而是通过组合对象实现的)。后面在讲到双亲委托机制时,读者就会明白了。

引导类加载器

引导类加载器是由原生的C++代码实现的,它不是继承ClassLoader得到的。引导类加载器加载的是jre/lib/rt.jar包下的类,加载java的核心类库

扩展类加载器

扩展类加载器继承了ClassLoader类,由sun.misc.Launcher$ExtClassLoader实现,负责加载的是jre/lib/ext/*.jar包里面的类。

系统类加载器

系统类加载器也继承了ClassLoader类,由sun.misc.Launcher$AppClassLoader 实现,负责加载java应用程序中的类,也就是我们自己编写的java类

自定义类加载器

自定义类加载器继承了ClassLoader类,由开发人员自己定义加载指定的类。

双亲委托机制

通过查看ClassLoader的源码,我们发现ClassLoader有个parent 成员变量,用来表示当前类加载器的上一级类加载器


当然也提供了一个方法用来返回parent对象:


在以上四种类加载器中,除了引导类加载器没有parent外,其他的类加载器具有parent。

package com.tiantang.classLoader;

public class TestClassLoader {
	
	public static void main(String[] args) {
		//获得当前的类加载器
		ClassLoader loader=ClassLoader.getSystemClassLoader();
		System.out.println(loader);
		//获得扩展类加载器
		System.out.println(loader.getParent());
		//引导类加载器(由于是原生代码实现的,所以在这里打印的是null)
		System.out.println(loader.getParent().getParent());
	}

}
测试结果:


这么多加载器,那在虚拟机中,当加载器加载类时是如何选择类加载器来加载类的呢?

这就涉及到双亲委托机制了,就是当类加载器收到要加载类的请求时,不管自己能不能加载,首先把加载请求交给父亲,如果父亲还有父亲,则再向上递交,直到最顶级的父亲,如果最顶级的父亲能加载就加载,不能加载就交给儿子,再判断儿子能否加载,如果不能,则再向下传递,直到请求再次回到最初的加载器时,如果还不能加载,就报异常。这样做同时保证了Java的安全性。为什么这么说呢?

比如,我们自己定义一个java.lang.String类,这样就相当于我们覆盖了jdk为我们提供的String类,这样我们就可以为所欲为的在自己定义的String里进行操作了,如果没有双亲委托机制,那么当加载器加载类时,就会加载我们定义的String类,而不会加载jdk里面的String类,这样就相当于我们修改了jdk源码,这样的java我们还能说安全吗?但有了双亲委托机制,一切就不一样了,当类加载器接到加载我们自定义的String类的请求信息时,会首先把请求给父亲去加载,父亲在交给父亲,直到引导类加载器,而由于java的核心类库里存在java.lang.Sring类,而引导类加载器负责加载的是java的核心类库,因此加载器就会加载Java核心类库中的String类,而不是我们自己定义的String类,这样我们自己定义的String类就无效了,保证了Java的安全性。这样我防止了我们修改java的源码。

说道修改源码,有读者可能会想到JavaEE中开发时我们怎么就能修改源码呢?尤其是在JavaWeb项目中当我们要实现权限的粗细粒度的控制时,就会自己定义与Struts2中一样的一个标签类,然后修改源代码,实现权限的粗细粒度控制,那这个时候怎么就实现了源码的修改了呢?这个时候大家就要注意到,JavaWeb是在服务器上运行的,例如tomcat,这个时候的类的加载是由tomcat来实现加载的,而tomcat中的类加载器的加载机制就不再是双亲委托机制了,因此我们可以在web项目中修改源代码了。

至于自定义加载器,笔者由于学习Java开发的时间较短,差不多半年吧,经历太少,目前还没碰到过自己定义类加载器,不过笔者倒是曾听一位老师讲过怎么自定义类加载器,后续笔者会再写一篇文章去描述怎么去自定义类加载吧,并写一个小练习吧,权当扩展一下眼界吧!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值