• JAVA基础知识之JVM-——类加载器


    类加载器负责将.class文件加载到内存,并为其创建java.lang.Class对象,这个对象就代表这个类。

    在Java中,通过包名+类名来唯一标识一个类,而在JVM中,要用 类加载器实例+包名+类名 来唯一标识一个类。 可见JVM中是不止一种类加载器的。

    在JVM中,类加载器是成层次结构的, 这种层次结构自上而下分别是根类加载器(BootstrapLoader),扩展类加载器(extensionLoader)和系统类加载器(systemLoader)还有用户自定义类加载器

    根类加载器(BootstrapLoader)

    负责加载JAVA核心类(例如tr.jar)。 根类加载器是由JVM自身实现的(C/C++),而不是JAVA实现,更不是java.lang.ClassLoader的子类。

    下面程序演示了根类加载器所加载的JAVA核心类库。

     1 package jvmTest;
     2 
     3 import java.net.URL;
     4 
     5 import sun.misc.Launcher;
     6 
     7 public class Boot {
     8     public static void main(String[] args) {
     9         /*
    10          * 这里有可能报错 Access restriction: The type 'Launcher' is not API
    11          * 只需要将 全局属性Project>preferences>java>Compiler>Errors/Warnings>
    12          * 把右侧的【Deprecated and restricted API>Forbidden reference的Error】置为【Warning】.
    13          */
    14         URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
    15         for(int i = 0; i < urls.length; i++) {
    16             System.out.println(urls[i].toExternalForm());
    17         }
    18     }
    19 }

    在我的环境中输入如下,

     1 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/bin/default/jclSC170/vm.jar
     2 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/se-service.jar
     3 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/math.jar
     4 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/jlm.jar
     5 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmorb.jar
     6 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmorbapi.jar
     7 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmcfw.jar
     8 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmpkcs.jar
     9 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmcertpathfw.jar
    10 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmjgssfw.jar
    11 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmjssefw.jar
    12 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmsaslfw.jar
    13 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmjcefw.jar
    14 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmjgssprovider.jar
    15 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmjsseprovider2.jar
    16 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmcertpathprovider.jar
    17 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/xmldsigfw.jar
    18 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/xml.jar
    19 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/charsets.jar
    20 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/resources.jar
    21 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/rt.jar
    22 file:/C:/Program%20Files%20(x86)/IBM/Java70/jre/lib/ibmgpu.jar
    View Code

    可以看到rt.jar包含在其中, 正因为加载了这些类库,我们才可以在程序中直接使用 System, String这样的类

    扩展类加载器(extensionLoader)

    负责加载来自JRE的扩展目录(jrelibext 或者 java.ext.dirs 系统属性指定的目录)中JAR包中的类, 我们也可以将自己的类放在这个目录下作为扩展类加载。

    系统类加载器(systemLoader)

    也称为应用类加载器, 负责加载下面几种类,

    • JVM启动时加载来自 java命令的 -classpath选项的JAR包
    • java.lang.path系统属性
    • CLASSPATH环境变量

    类的加载机制

    •  全盘负责

    当一个类加载器加载一个Class时,该Class所依赖的其他Class也将由相同类加载器加载。

    • 父类委托

    JVM加载一个Class时,会先使用其父类加载器来加载,所以一直迭代到最上层的加载器,一个类会最先由BootstrapLoader尝试加载,如果失败则由extensionLoader尝试加载,再失败则由systemLoader尝试加载,最后还失败则由自定义的类加载器来加载,如果依然失败,就会抛出错误。 父类委托机制可以防止类被重复加载,也更安全

    所以常规加载顺序如下图 (图片引用自 http://blog.csdn.net/xyang81/article/details/7292380)

     但是tomcat采用了完全相反的机制,先通过默认类加载器加载,如果失败,再找父类加载器加载。

    这篇文章这样描述tomcat的加载过程(http://ifeve.com/classloader/)

     下面例子演示了这种层次关系,

     1 package jvmTest;
     2 
     3 import java.net.URL;
     4 import java.util.Enumeration;
     5 
     6 public class Loader {
     7     public static void main(String[] args) throws Exception {
     8         // 获取系统类加载器
     9         ClassLoader scl = ClassLoader.getSystemClassLoader();
    10         System.out.println("系统类加载器(systemLoader): "+ scl);
    11         // 获取系统 类加载器 的路径,通常由环境变量CLASSPATH指定,如果操作系统未指定CLASSPATH,则取当前路径
    12         // 在ClassLoader类中定义的方法, public Enumeration<URL> getResources(String name)
    13         // Enumeration比较古老,比较少用到,多数情况下都已经被Iterator取代
    14         Enumeration<URL> eml= scl.getResources("");
    15         while(eml.hasMoreElements()) {
    16             System.out.println("系统加载器路径: "+eml.nextElement());
    17         }
    18         // 获取系统加载器的父加载器,得到扩展类加载器
    19         ClassLoader ecl = scl.getParent();
    20         System.out.println("扩展加载器(extensionLoader): "+ ecl);
    21         System.out.println("扩展加载器路径: "+ System.getProperty("java.ext.dirs"));
    22         System.out.println("扩展加载器的parent: "+ ecl.getParent());
    23     }
    24 }

    执行结果,

    1 系统类加载器(systemLoader): sun.misc.Launcher$AppClassLoader@4be822c2
    2 系统加载器路径: file:/C:/Users/IBM_ADMIN/PROJECT/CrazyJAVA/PROJECT_JavaBasic/bin/
    3 扩展加载器(extensionLoader): sun.misc.Launcher$ExtClassLoader@cb289176
    4 扩展加载器路径: C:Program Files (x86)IBMJava70jrelibext
    5 扩展加载器的parent: null

    执行结果可以看到扩展类加载器的parent从逻辑上来讲应该是根类加载器,但实际却是null,这是因为根类加载器是用C++实现的,JAVA无法直接访问。

    •  缓存机制

    缓存机制保证加载过的Class被缓存起来,当加载新类时,先进缓存查询是否已经加载,只有缓存中没有的时候才进行加载,这样会显著提高性能。

    reference

    深入浅出ClassLoader

    http://ifeve.com/classloader/

    深入分析Java ClassLoader原理

    http://blog.csdn.net/xyang81/article/details/7292380

  • 相关阅读:
    Qt助手---摘录
    Qt随记
    前端编码规范之CSS(转)
    给QT新手的练手项目——基于QT的GIF播放器(转)
    Qt收藏
    C++开发者都应该使用的10个C++11特性(转)
    为学Linux,我看了这些书(转)
    Qt去掉view项的焦点虚线框的方法(转)
    QTableWidget详解(样式、右键菜单、表头塌陷、多选等)(转)
    JZOJ 3085. 图的计数
  • 原文地址:https://www.cnblogs.com/fysola/p/6099088.html
Copyright © 2020-2023  润新知