ClassLoaderITeye - AG环亚娱乐集团

ClassLoaderITeye

2019年03月26日10时44分54秒 | 作者: 白亦 | 标签: 运用,文件,办法 | 浏览: 1886

ClassLoader首要对类的恳求供给效劳,当JVM需求某类时,它依据称号向ClassLoader要求这个类,然后由ClassLoader回来这个类的class目标。 1.1 几个相关概念ClassLoader担任载入体系的一切Resources(Class,文件,来自网络的字节约等),经过ClassLoader从而将资源载入JVM  

每个class都有一个reference,指向自己的ClassLoader。Class.getClassLoader()  

array的ClassLoader便是其元素的ClassLoader,若是根本数据类型,则这个array没有ClassLoader  

1.2 首要办法和作业进程Java1.1及早年版别中,ClassLoader首要办法:  

Class loadClass( String name, boolean resolve ); ClassLoader.loadClass() 是 ClassLoader 的进口点  

defineClass 办法是 ClassLoader 的首要窍门。该办法承受由原始字节组成的数组并把它转换成 Class 目标。原始数组包含如从文件体系或网络装入的数据。  

findSystemClass 办法从本地文件体系装入文件。它在本地文件体系中寻觅类文件,假如存在,就运用 defineClass 将原始字节转换成 Class 目标,以将该文件转换成类。当运转 Java 运用程序时,这是 JVM 正常装入类的缺省机制。  

resolveClass能够不彻底地(不带解析)装入类,也能够彻底地(带解析)装入类。当编写咱们自己的 loadClass 时,能够调用 resolveClass,这取决于 loadClass 的 resolve 参数的值  

findLoadedClass 充任一个缓存:当恳求 loadClass 装入类时,它调用该办法来查看 ClassLoader 是否已装入这个类,这样能够避免从头装入已存在类所形成的费事。应首要调用该办法  

一般load办法进程如下:  

 

调用 findLoadedClass 来查看是否存在已装入的类。  

假如没有,那么选用某种特其他奇特办法来获取原始字节。(经过IO从文件体系,来自网络的字节约等)  

假如已有原始字节,调用 defineClass 将它们转换成 Class 目标。  

假如没有原始字节,然后调用 findSystemClass 查看是否从本地文件体系获取类。  

假如 resolve 参数是 true,那么调用 resolveClass 解析 Class 目标。  

假如还没有类,回来 ClassNotFoundException。  

不然,将类回来给调用程序。  

1.3 托付模型自从JDK1.2今后,ClassLoader做了改善,运用了托付模型,一切体系中的ClassLoader组成一棵树,ClassLoader在载入类库时先让Parent寻觅,Parent找不到才自己找。  

JVM在运转时会发生三个ClassLoader,Bootstrap ClassLoader、Extension ClassLoader和App ClassLoader。其间,Bootstrap ClassLoader是用C++编写的,在Java中看不到它,是null。它用来加载中心类库,便是在lib下的类库,Extension ClassLoader加载lib/ext下的类库,App ClassLoader加载Classpath里的类库,三者的关系为:App ClassLoader的Parent是Extension ClassLoader,而Extension ClassLoader的Parent为Bootstrap ClassLoader。加载一个类时,首要BootStrap进行寻觅,找不到再由Extension ClassLoader寻觅,终究才是App ClassLoader。  

 

将ClassLoader规划成托付模型的一个重要原因是出于安全考虑,比如在Applet中,假如编写了一个java.lang.String类并具有损坏性。假如不选用这种托付机制,就会将这个具有损坏性的String加载到了用户机器上,导致损坏用户安全。但选用这种托付机制则不会呈现这种状况。由于要加载java.lang.String类时,体系终究会由Bootstrap进行加载,这个具有损坏性的String永久没有机会加载。  

 

托付模型还带来了一些问题,在某些状况下会发生混杂,如下是Tomcat的ClassLoader结构图:  

 

                Bootstrap 

                  | 

                System 

                  | 

                Common 

                /     

            Catalina  Shared 

                      /     

                   Webapp1  Webapp2 ... 

 

由 Common 类装入器装入的类决不能(依据称号)直接拜访由 Web 运用程序装入的类。使这些类联络在一起的仅有办法是经过运用这两个类集都可见的接口。在这个比如中,便是包含由 Java servlet 完结的 javax.servlet.Servlet。  

假如在lib或许lib/ext等类库有与运用中相同的类,那么运用中的类将无法被载入。一般在jdk新版别呈现有类库移动时会呈现问题,例如开端咱们运用自己的xml解析器,而在jdk1.4中xml解析器变成规范类库,load的优先级也高于咱们自己的xml解析器,咱们自己的xml解析器永久无法找到,将或许导致咱们的运用无法运转。  

 

相同的类,不同的ClassLoader,将导致ClassCastException反常  

 

1.4 线程中的ClassLoader每个运转中的线程都有一个成员contextClassLoader,用来在运转时动态地载入其它类,能够运用办法Thread.currentThread().setContextClassLoader(...);更改当时线程的contextClassLoader,来改动其载入类的行为;也能够经过办法Thread.currentThread().getContextClassLoader()来取得当时线程的ClassLoader。  

实际上,在Java运用中一切程序都运转在线程里,假如在程序中没有手艺设置过ClassLoader,关于一般的java类如下两种办法取得的ClassLoader一般都是同一个  

 

this.getClass.getClassLoader();  

Thread.currentThread().getContextClassLoader();  

办法一得到的Classloader是静态的,标明类的载入者是谁;办法二得到的Classloader是动态的,谁履行(某个线程),便是那个履行者的Classloader。关于单例形式的类,静态类等,载入一次后,这个实例会被许多程序(线程)调用,关于这些类,载入的Classloader和履行线程的Classloader一般都不同。  

 

1.5 Web运用中的ClassLoader回到上面的比如,在Tomcat里,WebApp的ClassLoader的作业原理有点不同,它先企图自己载入类(在ContextPath/WEB-INF/...中载入类),假如无法载入,再恳求父ClassLoader完结。  

由此可得:  

 

关于WEB APP线程,它的contextClassLoader是WebAppClassLoader  

关于Tomcat Server线程,它的contextClassLoader是CatalinaClassLoader  

1.6 取得ClassLoader的几种办法能够经过如下3种办法得到ClassLoader  

this.getClass.getClassLoader(); // 运用当时类的ClassLoader  

Thread.currentThread().getContextClassLoader(); // 运用当时线程的ClassLoader  

ClassLoader.getSystemClassLoader(); // 运用体系ClassLoader,即体系的进口点所运用的ClassLoader。(留意,system ClassLoader与根ClassLoader并不相同。JVM下system ClassLoader一般为App ClassLoader)  

1.7 几种扩展运用用户定制自己的ClassLoader能够完结以下的一些运用  

安全性。类进入JVM之前先经过ClassLoader,所以能够在这边查看是否有正确的数字签名等  

加密。java字节码很简单被反编译,经过定制ClassLoader使得字节码先加密避免他人下载后反编译,这儿的ClassLoader相当于一个动态的解码器  

归档。或许为了节约网络资源,对自己的代码做一些特其他归档,然后用定制的ClassLoader来解档  

自打开程序。把java运用程序编译成单个可履行类文件,这个文件包含紧缩的和加密的类文件数据,一起有一个固定的ClassLoader,当程序运转时它在内存中彻底自行解开,无需先装置  

动态生成。能够生成运用其他还未生成类的类,实时创立整个类并可在任何时刻引进JVM  

2.0 资源载入 

一切资源都经过ClassLoader载入到JVM里,那么在载入资源时当然能够运用ClassLoader,仅仅关于不同的资源还能够运用一些其他办法载入,例如关于类能够直接new,关于文件能够直接做IO等。 2.1 载入类的几种办法假定有类A和类B,A在办法amethod里需求实例化B,或许的办法有3种。关于载入类的状况,用户需求知道B类的完好姓名(包含包名,例如"com.rain.B")  

1. 运用Class静态办法 Class.forName  

 

    Class cls = Class.forName("com.rain.B"); 

    B b = (B)cls.newInstance(); 

 

2. 运用ClassLoader  

    /* Step 1. Get ClassLoader */ 

    ClassLoader cl; // 怎么取得ClassLoader参阅1.6 

 

    /* Step 2. Load the class */ 

    Class cls = cl.loadClass("com.rain.B"); // 运用第一步得到的ClassLoader来载入B 

     

    /* Step 3. new instance */ 

    B b = (B)cls.newInstance(); // 有B的类得到一个B的实例 

 

3. 直接new  

    B b = new B(); 

 

2.2 文件载入(例如配置文件等)假定在com.rain.A类里想读取文件夹 /com/rain/config 里的文件sys.properties,读取文件能够经过绝对途径或相对途径,绝对途径很简单,在Windows下以盘号开端,在Unix下以"/"开端  

关于相对途径,其相对值是相关于ClassLoader的,由于ClassLoader是一棵树,所以这个相对途径和ClassLoader树上的任何一个ClassLoader相对比较后能够找到文件,那么文件就能够找到,当然,读取文件也运用托付模型  

 

1. 直接IO  

 

/** 

 * 假定当时方位是 "C:/test",经过履行如下指令来运转A "java com.rain.A" 

 * 1. 在程序里能够运用绝对途径,Windows下的绝对途径以盘号开端,Unix下以"/"开端 

 * 2. 也能够运用相对途径,相对途径前面没有"/" 

 * 由于咱们在 "C:/test" 目录下履行程序,程序进口点是"C:/test",相对途径就 

 * 是 "com/rain/config/sys.properties" 

 * (比如中,当时程序的ClassLoader是App ClassLoader,system ClassLoader = 当时的 

 * 程序的ClassLoader,进口点是"C:/test") 

 * 关于ClassLoader树,假如文件在jdk lib下,假如文件在jdk lib/ext下,假如文件在环境变量里, 

 * 都能够经过相对途径"sys.properties"找到,lib下的文件最早被找到 

 */ 

File f = new File("C:/test/com/rain/config/sys.properties"); // 运用绝对途径 

//File f = new File("com/rain/config/sys.properties"); // 运用相对途径 

InputStream is = new FileInputStream(f); 

 

假如是配置文件,能够经过java.util.Properties.load(is)将内容读到Properties里,Properties默许以为is的编码是ISO-8859-1,假如配置文件对错英文的,或许呈现乱码问题。  

2. 运用ClassLoader  

 

/** 

 * 由于有3种办法得到ClassLoader,对应有如下3种办法读取文件 

 * 运用的途径是相关于这个ClassLoader的那个点的相对途径,此处只能运用相对途径 

 */ 

InputStream is = null; 

is = this.getClass().getClassLoader().getResourceAsStream( 

       "com/rain/config/sys.properties"); //办法1 

//is = Thread.currentThread().getContextClassLoader().getResourceAsStream( 

       "com/rain/config/sys.properties"); //办法2 

//is = ClassLoader.getSystemResourceAsStream("com/rain/config/sys.properties"); //办法3 

 

假如是配置文件,能够经过java.util.Properties.load(is)将内容读到Properties里,这儿要留意编码问题。  

3. 运用ResourceBundle  

 

    ResourceBundle bundle = ResourceBundle.getBoundle("com.rain.config.sys"); 

 

这种用法一般用来载入用户的配置文件,关于ResourceBunlde更具体的用法请参阅其他文档  

总结:有如下3种途径来载入文件  

 

    1. 绝对途径 - IO 

    2. 相对途径 - IO 

                - ClassLoader 

    3. 资源文件 - ResourceBundle 

 

2.3 怎么在web运用里载入资源在web运用里当然也能够运用ClassLoader来载入资源,但更常用的状况是运用ServletContext,如下是web目录结构  

    ContextRoot 

       |- JSP、HTML、Image等各种文件 

        |- [WEB-INF] 

              |- web.xml 

              |- [lib] Web用到的JAR文件 

                |- [classes] 类文件 

 

用户程序一般在classes目录下,假如想读取classes目录里的文件,能够运用ClassLoader,假如想读取其他的文件,一般运用ServletContext.getResource()  

假如运用ServletContext.getResource(path)办法,途径有必要以"/"开端,途径被解说成相关于ContextRoot的途径,此处载入文件的办法和ClassLoader不同,举例"/WEB-INF/web.xml","/download/WebExAgent.rar"

版权声明
本文来源于网络,版权归原作者所有,其内容与观点不代表AG环亚娱乐集团立场。转载文章仅为传播更有价值的信息,如采编人员采编有误或者版权原因,请与我们联系,我们核实后立即修改或删除。

猜您喜欢的文章

阅读排行

  • 1

    ClassLoaderITeye

    运用,文件,办法
  • 2
  • 3
  • 4

    手机号码校验合法性ITeye

    代表,必定,第二位
  • 5
  • 6

    Java 目标巨细的核算ITeye

    目标,巨细,字节
  • 7
  • 8
  • 9

    架构师之jdk8ITeye

    字符串,判别,如果
  • 10