ClassLoader原理

ClassLoader原理

Classloader体系结构

    系统自带的类加载器主要有:Bootstrap class loader、Extensions class loader、System class loader。

  1. Bootstrap class loader 负责加载” <JAVA_HOME>/jre/lib”目录的JAR包,如rt.jar等。该加载器使用C语言实现,不是Java代码实现的。
  2. Extensions class loader 负责加载” <JAVA_HOME>/jre/lib/ext”目录的Jar,这个加载器的是Java语言实现的,sun.misc.Launcher$ExtClassLoader,是个内部类。
  3. System class loader负责加载” java.class.path”目录类,这个类也是Java实现的,sun.misc.Launcher$AppClassLoader。

验证类加载器的层次结构:

    从上面可以看到HashMap是Null(因为不是Java语言实现,所以是Null),即是Bootstrap class loader加载,DNSNameService由Extensions class loader加载,当前类ClassLoaderTest由System class loader(AppClassLoader)加载。

类加载模型

    类加载是指Class文件加载到JVM并产生Class对象的远程。类加载,其实包括类和接口的加载,以下我们统一称为类加载。类加载使用双亲委派模型,即类加载器把要加载的类委派给其父加载器,父加载器再把要加载类委派给其父加载器,直到Bootstrap class loader为止。被委派的类加载器就形成了委派链,其中Bootstrap class loader称委派链的未端。如果要加载的类不在被委派的加载器职责范围,被委派的加载器返回null给其子一级加载器,由子一级的加载器加载,如果所以委派链都不加载,则由当前类加载器加载。

    如果被加载的类是类A,属于用户自定义类并在” java.class.path”路径下,假设当前类加载器是System class loader。那加载的流程是这样的:System class loader把类A委派给Extensions class loader,然后Extensions class loader又把类A委派给Bootstrap class loader,然后Bootstrap class loader发现类A不属于Bootstrap class loader加载范围内,返回Null给Extensions class loader, Extensions class loader也发现类A也不属于其加范围内,返回Null给System class loader,那System class loader尝试加载类A,得到类A的Class对象。

    如果被加载的类是类DNSNameService,属于dnsns.jar的<JAVA_HOME>/jre/lib/ext路径下,假设当前类加载器是System class loader。那加载的流程是这样的:System class loader把类DNSNameService委派给Extensions class loader,然后Extensions class loader又把类DNSNameService委派给Bootstrap class loader(注意,因为Extensions class loader不是委派链的未端,所以必须进行下一步委派),然后Bootstrap class loader发现类A不属于Bootstrap class loader加载范围内,返回Null给Extensions class loader, Extensions class loader也发现类DNSNameService属于其加范围内,加载DNSNameService,并返回DNSNameService的Class对换给System class loader,System class loader就可以直接使用DNSNameService的类了。

    如果被加载的类是类HashMap,属于dnsns.jar的<JAVA_HOME>/jre/lib/ext路径下,假设当前类加载器是System class loader。那加载的流程是这样的:System class loader把类HashMap委派给Extensions class loader,然后Extensions class loader又把类HashMap委派给Bootstrap class loader,然后Bootstrap class loader发现类HashMap属于Bootstrap class loader加载范围内(目录<JAVA_HOME>/jre/lib的rt.jar内),由Bootstrap class loader加载HashMap,并得到HashMap的Class对象,并把HashMap的Class对象返回给Extensions class loader,再由Extensions class loader返回给System class loader。

    异常情况,比如:黑客也写了一个带恶意HashMap的类,并且完全限定名也是java.util.HashMap。如果system class loader要加载这个带恶意的HashMap,先委派给Extensions class loader,然后再委派给Bootstrap class loader。 由于Bootstrap class loader负责的目录” <JAVA_HOME>/jre/lib ” 下已存在相同的完全限定名的HashMap,于是Bootstrap class loader只加载” <JAVA_HOME>/jre/lib ”目录下HashMap类,并创建Class对象,并返回给Extensions class loader,然后由Extensions class loader返回 System class loader。这样System class loader得到是一个安全的HashMap,而带恶意的HashMap则没有被丢弃了,没有被加载,避免了被入侵的危险。

    可以看到出委派模型的优点是安全,避免JRE自带的内置的类被外来的类覆盖。从上图可以看出,委派模型决定加载器优先级,优先级最高是Bootstrap class loader,其次是Extensions class loader,然后是System class loader,最后才是用户自定义的类。

类加载器的命名空间

    每个类加载器都拥用自己的命名空间,只有在同一个命名空间的类才能互相引用和转换(Cast),即同一个命名空间下的类才互相可见。其实,JVM的方法区内,会为每个类加载器维护一个表,表记录当前加载器的所加载的类。父加载器的命名空间的类对子加载器是可见的,就是说子加载器可见类范围是最大的,所有父 (包括多级父类)加载器加载的类对子类是可见的。所以子类的加载器的类可以引用父加载器的类,反之不成立。兄弟类加载器的命名空间之间的类是不可见的。比如:ClassLoaderA和ClassLoaderB均为System class loader的子加载器,ClassLoaderA加载类A,ClassLoaderB加载类B,此时类A和类B是不可见的,即不能互相引用,否则会报异常。这种错误非常隐蔽,很难发现,特别是当系统存在多个加载器时,特别要谨慎。

关联类加载

    JVM默认当前使用类的加载器去加载被引用的类。假设A类的加载器为:System class loader,比如:A类(使用类)引用了B类(引用类),那JVM默认使用System class loader加载B类,当然,加载类B时同样会使用双亲委派的模型。大家所熟悉的Class.forName方法,也是使用这个规则去加载类。在使用Class.forName时会使用当前类的加载器去加载目标类。

类加载器的选择

    估计大家接触得最多是context classLoader、System class loader、Class.forName三种方式,看完下面这两篇文章就明白了吧,我就不啰嗦了。

https://www.javaworld.com/article/2077344/core-java/find-a-way-out-of-the-classloader-maze.html?page=1

https://stackoverflow.com/questions/1771679/difference-between-threads-context-class-loader-and-normal-classloader

转载于:https://my.oschina.net/u/3627055/blog/1577960

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值