`

ClassLoader原理

    博客分类:
  • java
阅读更多

JVM规范定义了两种类型的类装载器:启动内装载器(bootstrap)和用户自定义装载器(user-defined class loader)

一.    ClassLoader基本概念
1ClassLoader分类
类装载器是用来把类(class)装载进JVM的。
JVM规范定义了两种类型的类装载器:启动内装载器(bootstrap)和用户自定义装载器(user-defined class loader)


JVM在运行时会产生三个ClassLoader:Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader.Bootstrap是用C++编写的,我们在Java中看不到它,是null,是JVM自带的类装载器,用来装载核心类库,如java.lang.*等。
AppClassLoaderParentExtClassLoader,而ExtClassLoaderParentBootstrap ClassLoader
 
Java提供了抽象类ClassLoader,所有用户自定义类装载器都实例化自ClassLoader的子类。 System Class Loader是一个特殊的用户自定义类装载器,由JVM的实现者提供,在编程者不特别指定装载器的情况下默认装载用户类。系统类装载器可以通过ClassLoader.getSystemClassLoader() 方法得到。
 
例1,测试你所使用的JVM的ClassLoader
/*LoaderSample1.java*/

public   class  LoaderSample1 {
    
public   static   void  main(String[] args) {
        Class c;
        ClassLoader cl;
        cl 
=  ClassLoader.getSystemClassLoader();
        System.out.println(cl);
        
while  (cl  !=   null ) {
            cl 
=  cl.getParent();
            System.out.println(cl);
        }
        
try  {
            c 
=  Class.forName( " java.lang.Object " );
            cl 
=  c.getClassLoader();
            System.out.println(
" java.lang.Object's loader is  "   +  cl);
            c 
=  Class.forName( " LoaderSample1 " );
            cl 
=  c.getClassLoader();
            System.out.println(
" LoaderSample1's loader is  "   +  cl);
        } 
catch  (Exception e) {
            e.printStackTrace();
        }
    }
}


在我的机器上(Sun Java 1.4.2)的运行结果
sun.misc.Launcher$AppClassLoader@1a0c10f
sun.misc.Launcher$ExtClassLoader@e2eec8
null
java.lang.Object's loader is null
LoaderSample1's loader is sun.misc.Launcher$AppClassLoader@1a0c10f

第一行表示,系统类装载器实例化自类sun.misc.Launcher$AppClassLoader
第二行表示,系统类装载器的parent实例化自类sun.misc.Launcher$ExtClassLoader
第三行表示,系统类装载器parent的parent为bootstrap
第四行表示,核心类java.lang.Object是由bootstrap装载的
第五行表示,用户类LoaderSample1是由系统类装载器装载的
 
 
二.parent delegation模型
从1.2版本开始,Java引入了双亲委托模型,从而更好的保证Java平台的安全。在此模型下,当一个装载器被请求装载某个类时,它首先委托自己的parent去装载,若parent能装载,则返回这个类所对应的Class对象,若parent不能装载,则由parent的请求者去装载

图 1 parent delegation模型
如图1所示,loader2的parent为loader1,loader1的parent为system class loader。假设loader2被要求装载类MyClass,在parent delegation模型下,loader2首先请求loader1代为装载,loader1再请求系统类装载器去装载MyClass。若系统装载器能成功装载,则将MyClass所对应的Class对象的reference返回给loader1,loader1再将reference返回给loader2,从而成功将类MyClass装载进虚拟机。若系统类装载器不能装载MyClass,loader1会尝试装载MyClass,若loader1也不能成功装载,loader2会尝试装载。若所有的parent及loader2本身都不能装载,则装载失败。
 
若有一个能成功装载,实际装载的类装载器被称为定义类装载器,所有能成功返回Class对象的装载器(包括定义类装载器)被称为初始类装载器。如图1所示,假设loader1实际装载了MyClass,则loader1为MyClass的定义类装载器,loader2和loader1为MyClass的初始类装载器。
 
需要指出的是,Class Loader是对象,它的父子关系和类的父子关系没有任何关系。
 
那么parent delegation模型为什么更安全了?因为在此模型下用户自定义的类装载器不可能装载应该由父亲装载器装载的可靠类,从而防止不可靠甚至恶意的代码代替由父亲装载器装载的可靠代码。实际上,类装载器的编写者可以自由选择不用把请求委托给parent,但正如上所说,会带来安全的问题。
 
 
三.命名空间及其作用
每个类装载器有自己的命名空间,命名空间由所有以此装载器为创始类装载器的类组成。不同命名空间的两个类是不可见的,但只要得到类所对应的Class对象的reference,还是可以访问另一命名空间的类。
 
例2演示了一个命名空间的类如何使用另一命名空间的类。在例子中,LoaderSample2由系统类装载器装载,LoaderSample3由自定义的装载器loader负责装载,两个类不在同一命名空间,但LoaderSample2得到了LoaderSample3所对应的Class对象的reference,所以它可以访问LoaderSampl3中公共的成员(如age)。
例2不同命名空间的类的访问
/*LoaderSample2.java*/

import  java.net. * ;
import  java.lang.reflect. * ;
public   class  LoaderSample2 {
    
public   static   void  main(String[] args) {
        
try  {
            String path 
=  System.getProperty( " user.dir " );
            URL[] us 
=  { new  URL( " file:// "   +  path  +   " /sub/ " )};
            ClassLoader loader 
=   new  URLClassLoader(us);
            Class c 
=  loader.loadClass( " LoaderSample3 " );
            Object o 
=  c.newInstance();
            Field f 
=  c.getField( " age " );
            
int  age  =  f.getInt(o);
            System.out.println(
" age is  "   +  age);
        } 
catch  (Exception e) {
            e.printStackTrace();
        }
    }
}


/*sub/Loadersample3.java*/

public   class  LoaderSample3 {
    
static  {
        System.out.println(
" LoaderSample3 loaded " );
    }
    
public   int  age  =   30 ;
}

编译:javac LoaderSample2.java; javac sub/LoaderSample3.java
运行:java LoaderSample2
LoaderSample3 loaded
age is 30
从运行结果中可以看出,在类LoaderSample2中可以创建处于另一命名空间的类LoaderSample3中的对象并可以访问其公共成员age。
运行时包(runtime package)
由同一类装载器定义装载的属于相同包的类组成了运行时包,决定两个类是不是属于同一个运行时包,不仅要看它们的包名是否相同,还要看的定义类装载器是否相同。只有属于同一运行时包的类才能互相访问包可见的类和成员。这样的限制避免了用户自己的代码冒充核心类库的类访问核心类库包可见成员的情况。假设用户自己定义了一个类java.lang.Yes,并用用户自定义的类装载器装载,由于java.lang.Yes和核心类库java.lang.*由不同的装载器装载,它们属于不同的运行时包,所以java.lang.Yes不能访问核心类库java.lang中类的包可见的成员。
 
总结
命名空间并没有完全禁止属于不同空间的类的互相访问,双亲委托模型加强了Java的安全,运行时包增加了对包可见成员的保护。
 
二.    扩展ClassLoader方法
我们目的是从本地文件系统使用我们实现的类装载器装载一个类。为了创建自己的类装载器我们应该扩展ClassLoader类,这是一个抽象类。我们创建一个FileClassLoader extends ClassLoader。我们需要覆盖ClassLoader中的findClass(String name)方法,这个方法通过类的名字而得到一个Class对象。

     public  Class findClass(String name)
    {
        
byte [] data  =  loadClassData(name);
        
return  defineClass(name, data,  0 , data.length);
    }


   我们还应该提供一个方法loadClassData(String name),通过类的名称返回class文件的字
节数组。然后使用ClassLoader提供的defineClass()方法我们就可以返回Class对象了。

     public   byte [] loadClassData(String name)
    {
        FileInputStream fis 
=   null ;
        
byte [] data  =   null ;
        
try
        {
            fis 
=   new  FileInputStream( new  File(drive  +  name  +  fileType));
            ByteArrayOutputStream baos 
=   new  ByteArrayOutputStream();
            
int  ch  =   0 ;
            
while  ((ch  =  fis.read())  !=   - 1 )
            {
                baos.write(ch);
               
            }
            data 
=  baos.toByteArray();
        } 
catch  (IOException e)
        {
            e.printStackTrace();
        }
        
        
return  data;
    }
分享到:
评论

相关推荐

    Java ClassLoader原理

    Sun 官方关于 ClassLoader原理的文章,值得一看

    webshpere classloader 原理

    详细说明了websphere classloader 的架构与实现

    Android 使用classloader原理进行热更新

    使用Android的classloader加载器实现热更新,通过反射机制获取到源码的Elements数组替换classes.dex实现更新,只能重启软件进行更新,无法实现实时更新。

    Java classloader原理深究

    前面已经写过一篇关于java classloader的拙文java classloader原理初探。  时隔几年,再看一遍,觉得有些地方显得太过苍白,于是再来一篇:  完成一个Java类之后,经过javac编译,会生成一个class文件,这个...

    ClassLoader类加载机制和原理详解

    ClassLoader类加载机制和原理详解

    Java ClassLoader 原理详细分析

    一、什么是ClassLoader?  大家都知道,当我们写好一个Java程序之后,不是管是CS还是BS应用,都是由若干个.class文件组织而成的一个完整的Java应用程序,当程序在运行时,即会调用该程序的一个入口函数来调用系统的...

    【图解版】深入分析ClassLoader类加载工作机制

    【图解版】深入分析ClassLoader类加载工作机制,从原理到JVM的装载过程,详情分析了ClassLoader加载类以及自定义类加载器的过程,不可用于商业用途,如有版权问题,请联系删除!

    ClassLoader 详解.doc

    关于J2EE服务器的ClassLoader的原理,该文档清晰了揭示了jvm装载类的顺序,同时用户可以自定义修改classLoader的配置 通过该文档,可以加深对Java虚拟机的理解

    ClassLoader加载机制

    该电子书详细介绍了java虚拟机类加载机制,对于深入理解jvm工作原理有很好的帮助作用,对于初学java,有一定工作经验的小伙伴来说是一本提高自身java素养,夯实自己java基本技能的“葵花宝典”。

    jboss 5 原理 2 classloader

    JBoss has always had a unique way of dealing with classloading, and the new classloading layer that comes with Microcontainer is no exception (keep in mind that you can use Microcontainer without ...

    java自定义类加载classloader文档,包括代码

    java自定义类加载classloader文档,包括代码,以及详细的原理及过程

    Java_ClassLoader详解

    Java_ClassLoader详解,解说java类的加载的原理,让你轻松了解java的类加载

    论文研究-ClassLoader加密技术改进研究 .pdf

    ClassLoader加密技术改进研究,徐首泽,金瓯,ClassLoader加密技术是Java当中用的比较广泛的代码保护技术,本文分析了ClassLoader加密技术的原理,发现并分析了现有方法存在的漏洞,同�

    Java中ClassLoader类加载学习总结

    本篇文章主要给大家讲述了Java中ClassLoader类加载的原理以及用法总结,一起学习下。

    Java类加载原理解析

    Java类加载原理解析 classloader

    深入JVM内核 - 原理、诊断与优化

    详细介绍ClassLoader的原理和应用。分析2个案例,说明ClassLoader的使用。 第七课 性能监控工具 线程死锁分析 OOM分析 介绍常用的JVM诊断和分析工具,并以死锁和OOM为例,展示这些工具的使用。 第八课 分析Java...

    Java虚拟机类装载:原理、实现与应用

    类的动态装载机制是JVM的一...本文介绍了JVM中类装载的原理、实现以及应用,尤其分析了ClassLoader的结构、用途以及如何利用自定义 的ClassLoader装载并执行Java类,希望能使读者对JVM中的类装载有一个比较深入的理解。

    java的ClassLoader类加载器机制

    jvm运行的过程中,需要载入类,而类的加载需要类加载器,本文章提供了java的类加载器的工作原理。可以使读者更加理解jvm的运行机制。

Global site tag (gtag.js) - Google Analytics