zoukankan      html  css  js  c++  java
  • 浅谈java classloader

    本文由作者张远道授权网易云社区发布。


    类加载器三杰


    jvm有三类classloader,分别是bootstrap classloader,extended classloader以及system classloader。

    bootstrap classloader是系统在启动jvm时默认加载的。当用户在命令行输入java Test时,系统会首先加载jvm。在windows系统下,jvm的路径通常位于%JAVA_HOME%/jdk/jre/client/jvm.dll和%JAVA_HOME%/jdk/jre/server/jvm.dll.

    bootstrap classloader加载后,会载入extended classloader,并将extended classloader的父类设为bootstrap classloader。然后,bootstrap classloader接着载入system classloader,并将system classloader的父类设为extended classloader。至此,bootstrap--extended--system三级继承结构形成。

    bootstrap classloader在jvm启动之后自动加载。bootstrap  classloader由c实现,不属于java类。

    extended classloader由java实现,通常为sun.misc.Lancher$ExtClassLoader.

    system classloader由java实现,通常为sun.misc.Lancher$AppClassLoader.

    其中,

    • bootstrap classloader负责加载sun.boot.class.path路径下的.class文件以及jar包。

    • extended classloader负责加载java.ext.dirs路径下的.class文件以及jar包。

    • system classloader负责加载java.class.path路径下的.class文件以及jar包。

    sun.boot.class.path通常对应环境变量CLASSPATH的路径。

    java.ext.dirs通常对应JAVA_HOME/jre/lib/ext目录。

    java.class.path对应用户自身的类路径。


    类加载到何处


    据可靠情报,jvm由方法区,堆,栈,pc寄存器和本地方法栈构成。类加载器的任务就是将class二进制文件加载到方法区,供虚拟机模制出在堆中存放的对象。


    双亲委托机制


    classloader加载类的过程为:

    1. 检查被加载类是否被加载。

    2. 如果没有被加载则调用父classloader加载该类。

    3. 如果1、2不成功,则仍由自身进行类加载。

    这种机制又叫双亲委派机制

    双亲委派机制的好处是,避免多个类加载器加载同一个类的不同拷贝到内存(jvm的方法区)中。因为如果类A由ClassLoaderA加载,同时,又被ClassLoaderB加载,这样,内存中就会存在两份不同的A的定义,于是形成A既是ClassLoaderA罩的,又是ClassLoaderB罩着,造成灾难性后果。

    用户自定义类的加载顺序通常为:

    首先调用AppClassLoader加载类,AppClassLoader调用ExtClassLoader,ExtClassLoader调用BootClassLoader,BootClassLoader在sun.boot.class.path寻找改类,没找到,加载失败;ExtClassLoader也未加载类,失败,最后由AppClassLoader加载成功。从这个加载顺序可以看出来,三个类加载器的对类的可见性是不同的。

    java中的类是由java的全名以及类的classloader来限定的。只有当二者完全一样才会认为是同一个类。否则是不同的类。因此,可以定义一个同名的类,包名也一样,只要保证该类被不同的类加载器加载即可。


    当前类加载器和线程上下文类加载器


    当前类加载器

    当前类加载器是指当前方法所在的类使用的类加载器。在程序中使用Class.forName或者Class.getResource抑或Class.class时就是使用的该类加载器。

    线程上下文类加载器

    线程上下文类加载器可以不遵循双亲委派机制。线程的上下文类加载器有Thread.currentThread().setContextClassLoader()来为当前线程设置线程上下文类加载器。如果没有设置当前线程的上下文类加载器,则继承父类的上下文类加载器。

    为什么还需要线程上下文类加载器?

    考虑一种情况,当我们的程序必须由jvm的核心代码去加载第三方类的时候。比如jndi,jndi的核心是rt.jar包中实现的,由Bootstrap classloader负责加载,但是jndi必须加载第三方厂商的具体的jndi实现,这个时候调用Bootstrap加载只对其子类加载器可见的类,就会出现失败。这个时候就可以使用线程上下文类加载器。 



    免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐

    更多网易技术、产品、运营经验分享请访问网易云社区


    相关文章:
    【推荐】 MongoDB的正确使用姿势
    【推荐】 扫脸动画
    【推荐】 AndroidTV开发(4)

  • 相关阅读:
    Erlang in Delphi 项目发布!
    云计算将如何改变世界
    win2000server IIS和tomcat5多站点配置
    实践中整理出tomcat集群和负载均衡
    VCL已死,RAD已死(6) 结语与预测
    window下tomcat集群和负载均衡
    团队开发经验:如何带领一个项目团队并做好项目总结 !!
    Install latest R for ubuntu
    P1297 单选错位
    P5322 排兵布阵
  • 原文地址:https://www.cnblogs.com/163yun/p/10118467.html
Copyright © 2011-2022 走看看