zoukankan      html  css  js  c++  java
  • 潜水 java类加载器ClassLoader

    类加载器(class loader)用于装载 Java 类到 Java 虚拟机中。一般来说。Java 虚拟机使用 Java 类的方式例如以下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类载入器负责读取 Java 字节代码。并转换成java.lang.Class类的一个实例。每一个这种实例用来表示一个 Java 类。

    通过此实例的 newInstance()方法就能够创建出该类的一个对象,也就是万能的Class对象。

    Java 中的类载入器大致能够分成两类。一类是系统提供的,另外一类则是由 Java 应用开发者编写的。系统提供的类载入器主要有以下三个:

    • 引导类载入器(bootstrap class loader):它用来载入 Java 的核心库。是用原生代码来实现的。并不继承自 java.lang.ClassLoader
    • 扩展类载入器(extensions class loader):它用来载入 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库文件夹。该类载入器在此文件夹里面查找并载入 Java 类。

    • 系统类载入器(system class loader):它依据 Java 应用的类路径(CLASSPATH)来载入 Java 类。一般来说,Java 应用的类都是由它来完毕载入的。

      能够通过 ClassLoader.getSystemClassLoader()来获取它。

    以下这段代码的输出结果能够显示出classloader的树状组织结构。
    public class ClassLoaderTest {
    	public static void main(String[] args){
    		 ClassLoader loader = ClassLoaderTest.class.getClassLoader(); 
    	        while (loader != null) { 
    	            System.out.println(loader.toString()); 
    	            loader = loader.getParent(); 
    	        } 
    	}
    }

    当中loader,toString()方法的返回值等同于以下的表达式:

     getClass().getName() + '@' + Integer.toHexString(hashCode())
    
    程序的输出例如以下:

    sun.misc.Launcher$AppClassLoader@70a0afab
    sun.misc.Launcher$ExtClassLoader@456d3d51

    第一个输出的是 ClassLoaderTree类的类载入器,即系统类载入器。它是 sun.misc.Launcher$AppClassLoader类的实例;第二个输出的是扩展类载入器。是 sun.misc.Launcher$ExtClassLoader类的实例。

    须要注意的是这里并没有输出引导类载入器。这是因为有些 JDK 的实现对于父类载入器是引导类载入器的情况,getParent()方法返回 null

    在了解了类载入器的树状组织结构之后,以下介绍类载入器的代理模式。

    classloader 载入类用的是全盘负责托付机制。所谓全盘负责,即是当一个classloader载入一个Class的时候,这个Class所依赖的和引用的全部 Class也由这个classloader负责载入。除非是显式的使用另外一个classloader载入;托付机制则是先让parent(父)类载入器 (而不是super,它与parent classloader类不是继承关系)寻找。仅仅有在parent找不到的时候才从自己的类路径中去寻找。

    此外类载入还採用了cache机制。也就是假设 cache中保存了这个Class就直接返回它,假设没有才从文件里读取和转换成Class,并存入cache。这就是为什么我们改动了Class可是必 须又一次启动JVM才干生效的原因。

    每一个ClassLoader载入Class的过程是:
    1.检測此Class是否加载过(即在cache中是否有此Class),假设有到8,假设没有到2
    2.假设parent classloader不存在(没有parent,那parent一定是bootstrap classloader了),到4。假设存在。到3
    3.请求parent classloader加载,假设成功到8。不成功到5
    4.请求jvm从bootstrap classloader中加载,假设成功到8
    5.寻找Class文件(从与此classloader相关的类路径中寻找)。找到了到6。假设找不到则到7.
    6.从文件里加载Class,到8.
    7.抛出ClassNotFoundException.
    8.返回Class.

    总结一下。类载入器的顺序是:
    先是bootstrap classloader。然后是extension classloader,最后才是system classloader。这样做的原因是出于安全性的考虑。试想假设system classloader“亲自”载入了一个具有破坏性的“java.lang.System”类的后果吧。

    这种托付机制保证了用户即使具有一个这种类, 也把它增加到了类路径中,可是它永远不会被载入。由于这个类总是由bootstrap classloader来载入的。大家能够运行一下下面的代码:
       System.out.println(System.class.getClassLoader());
    将会看到结果是null,这就表明java.lang.System是由bootstrap classloader载入的,由于bootstrap classloader不是一个真正的ClassLoader实例。而是由JVM实现的,正如前面已经说过的。



    简而言之,就是自底向上检查类是否已经被载入,然后自顶向下尝试载入类。


    值得一提的是tomcat的webappclassloader 这个相当于用户自己定义载入器,为每一个部署在独立tomcat实例上的web应用而创建。该载入器载入的类对于自身应用中的类都是可见的但对于其它web应用不可见,它负责载入以下路径中的类

    /WEB-INF/classes
    /WEB-INF/lib

    和java中的载入类的代理模式方式不同,webapp类载入器採用的是还有一种类载入模式(Servlet 2.4规范9.7.2节 web Application Classloader中建议使用这样的方式),当一个request对象载入一个由webappClassloader负责载入的类时,webappClassloader 将首先在本地库(WEB-INF)进行搜索。与传统的托付给父载入器进行搜索的方式不同。



  • 相关阅读:
    How To Build CyanogenMod Android for smartphone
    CentOS安装Code::Blocks
    How to Dual boot Multiple ROMs on Your Android SmartPhone (Upto Five Roms)?
    Audacious——Linux音乐播放器
    How to Dual Boot Multiple ROMs on Your Android Phone
    Everything You Need to Know About Rooting Your Android Phone
    How to Flash a ROM to Your Android Phone
    什么是NANDroid,如何加载NANDroid备份?
    Have you considered compiled a batman-adv.ko for android?
    BATMAN—Better Approach To Mobile Adhoc Networking (B.A.T.M.A.N.)
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/5040740.html
Copyright © 2011-2022 走看看