`
andyliuxs
  • 浏览: 136584 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

JVM(类加载器)

阅读更多
从网上看到得这一系列的文章,感觉不错就转过来供自己深入了解java使用



     类加载器是沙箱的第一道防线,毕竟代码都是由它装入jvm中的,其中也包括有危险的代码。它的安全作用有三点:

一 保护善意代码不受恶意代码的干扰
二 保护已验证的类库
三 代码放入有不同的行为限制的各个保护域中



      类加载体系通过使用不同的类加载器把类放入不同的名字空间中从而保护善意代码不受恶意代码的干扰。

     JVM为每个类加载器维护一个名字空间。例如,如果jvm在某个名字空间中加载了一个称为volcano的类,就不能再在这个名字空间中加载另一个也称为volcano的类,除非你再创建另一个名字空间。也就是说,如果jvm有三个名字空间,你就可以加载三个叫做volcano的类,一个名字空间一个。

     在jvm中,同一个名字空间中的类是可以直接交互的,但在不同名字空间中的类就不行,除非提供另外的机制。这样,名字空间就起到了一个屏障的作用。

     在图3-1中(转载的地方就没图,也不知道网上相同的源头在哪里),显示了两个名字空间,各有一个类加载器,各加载了两个类型,两个名字空间都有一个叫做volcano的类型。左边颜色较深的类加载器加载了类型climber和volcano,右边颜色较浅的类加载器加载了类型bakingsoda和volcano。图中的箭头表示名字空间中的名字对在方法区(method area)中对应类型定义数据的引用。因为名字空间的屏障作用,当climber引用volcano时,是指的同一个名字空间中的volcano。尽管都在同一个jvm,它也无法知道另一个名字空间中的volcano。如果想知道如何达到名字空间的分隔的,可以看第八章“链接模式”(估计需要看哪本书吧,不过都没说出自哪本书,我倒是想看看)

     类加载器体系可以通过使用不同的类加载器加载可信包(trusted packages)和不可信包(untrusted packages)从而保护可信包的安全。尽管你可以对同一包中的类型制定访问控制,但这种控制只有在被同一个加载器加载的前提下才起作用。

     通常,一个用户定义的类加载器需要依赖其他类加载器来完成任务,至少需要一个在jvm启动时创建的类加载器,这个类加载器称为启动类加载器。在1.2版本以前,类加载器必须显示的调用其他类加载器,如调用其他用户定义的类加载器的loadClass方法,或者调用启动类加载器(bootstrap class loader)的静态函数findSystemClass()。
在1.2版本中,一个类加载器要求另一个类加载器加载某个类型的过程被规范化为代理模式(parent-delegation model 译者:就是Chain of Responsibility模式)

    在某个类加载器试图以自己的方式加载一个类时,它首先缺省把这个工作交给自己的父对象。而这个父对象又会首先把这个任务交给自己的父对象处理,这样这个任务会一直传到启动类加载器,因为启动类加载器通常是代理链的最后一个类。如果父类加载器能够加载这个类型,就会返回此类型,否则由子类加载器处理。
在1.2版本以前的多数jvm的实现中,内建类加载器负责加载本地可用的类文件,通常包括java应用的类文件和所有这个应用需要的库,尽管加载所需类文件的方式根据应用不同而不同,但许多应用都以class path定义的路径来搜寻所需类文件。

    在1.2版本中,加载本地可用类文件的任务被分解给了多个类加载器。以前称为原始类加载器(primordial class loader)的类加载器被改称为启动类加载器,用来表示它只用来加载核心java api的类文件,因为核心java api类文件是用来启动jvm的。

    而负责加载其他类文件的任务都给了用户定义的类加载器(译者:这里指广义用户,包括虚拟机的实现者),这些类文件包括应用的类文件,用来进行安装和下载的标准扩展类文件,用来在class path中查找库的类文件等等。
因此当1.2的JVM开始运行时,它会创建至少一个用户定义的类加载器,所有的这些类加载器串成一个链,在链的头部是启动类加载器,在链的尾部是系统类加载器(system class loader)。在1.2之前,有时称内建类加载器为系统类加载器,在1.2,这个名字被更正式的用于称呼java应用所创建的新的类加载器的父亲。

    这个缺省父代理通常来加载应用的初始类,但任何用户定义的类加载器都可能被java平台的设计者所改变。
例如,假如你写了一个应用,此应用需要安装一个类加载器,用来加载从网络上下载的类文件。这个应用运行在一个jvm上,而这个jvm有两个用户定义的类加载器,一个是安装扩展类加载器,另一个是类路径类加载器。它们和启动类加载器串成一个链,依次为:启动类加载器,安装扩展类加载器,类路径加载器。

    如图3-2,类路径加载器被设计成了系统类加载器,它将是java应用新的类加载器的父亲。当你的应用的网络类加载器被安装时,它将这个系统类加载器设为它的父亲。

    假如在java应用运行中需要加载一个称为volcano的类,你的类加载器会首先把这一任务交给它的父亲,类路径类加载器,去查找和加载这个类文件。而类路径类加载器同样首先交给自己的父亲,安装扩展类加载器,去完成任
务。这样,这个任务最后交给启动类加载器去首先尝试处理。

   假设类volcano不是java api的一部分,也不是安装扩展和类路径的一部分,所有对应的类加载器都没有返回这个类型,这样就轮到你自己的类加载器了。它将会从网络上下载此类文件,这样这个类就称为你应用中的一部分了。
   我们继续这个例子,假如以后某个时候第一次调用了类volcano的一个方法,这个方法中引用了java api中的类java.util.HashMap,而这个类是这个应用第一次引用,这样jvm就要求你的类加载器去加载这个类。象以前一样,这个请求最终到达了启动类加载器。

   但这次不同,启动类加载器能够加载java.util.Hashmap并把它返回给了你的类加载器。这样安装扩展类加载器和类路径类加载器只起到了一个传递的作用,而你的类加载器也不用从网络下载这个类文件了。从此,在类volcano中,所有对java.util.Hashmap的引用都会使用这个类。

   有了这个背景知识,我们就可以看看类加载器是如何被用来保护可信库(trusted libraries)的了。类加载器体系通过防止不可信类冒充可信类保护了可信类的边界,防止了对java runtime安全的潜在威胁。
   有了这个链状的代理关系,我们知道,要加载一个类,需要链上的类加载器按特定顺序逐次检查,这样自己定义的类加载器始终处于一个较低优先级的状态,如果你自己的类加载器想要从网络上下载一个叫做java.lang.Integer的类是不可能的。它只能使用从父类加载器传来的类型。通过这种方法,防止了用不可信代码替换可信代码的发生。

   但假如代码不准备去替换一个可信类型,而只想在可信包中插入一个新类型呢?假如在前面例子中,你的网络类加载器想加载一个叫做java.lang.Virus的类。象以前一样,加载类的要求在链内传递,直到启动类加载器,尽管启动类加载器负责加载核心java api的类,其中也包括一个叫java.lang的包名,但找不到Virus,我们假设这个类同样在安装扩展类加载器和类路径类加载器中也没有找到。这样你的网络类加载器就从网络上下载了这个类。
   假设你成功下载了类java.lang.Virus,Java对在同一个包中的类的相互访问有一定的特权。因此,因为你的类加载器加载了一个无耻的宣称自己是java api的一部分的类java.lang.Virus,你肯定希望能够享受到某种特权,从而干一些罪恶的勾当。但类加载机制制止了这种事情的发生,因为类加载机制限制这种特权只有在同一个类加载器加载的前提下。

因为java api的java.lang包中的可信类都由启动类加载器加载,而邪恶的java.lang.Virus由你的网络类加载器加载,他们并不属于同一个运行包(runtime package)。

   运行包这个术语首次在jvm第二版的规范中引入,指由同一个类加载器加载的同一个包中的所以类型。
在允许同一个包中的两个类型访问之前,jvm还有确信此两个类型是由同一个类加载器加载的。
    因此,jvm不允许java.lang.Virus去访问java api中java.lang 包中的其他类型,因为他们不是由同一个类加载器加载的。

    引入运行包的目的之一就是使用不同的类加载器加载不同类型的类文件。启动类加载器用来加载最值得信赖的核心java api。安装扩展类加载器用来加载安装扩展的任何类文件。虽然安装扩展也是可以信赖的,但还没有到可以向java api添加新类型的程度。同样,类路径类加载器加载的类也不能访问安装扩展和java api中的类型。

    类加载器也可以简单的禁止加载某些类型来保护可信代码。

    例如,你可能安装了某些包,其中有一些类你想由类路径类加载器来加载,而不是你的网络类加载器。
     假设你创建一个叫做absolutepower的包,并把它安装在了类路径类加载器的访问范围内。同时你希望由你的类加载器加载的类不能加载absolutepower包中任何类。这样在你的类加载器中的第一件事就是检查需要加载的类是不是把自己声明为absolutepower中的类,如果是,则抛出一个异常,并不是交给父类加载器来处理。
类加载器机制除了屏蔽不同名字空间,保护可信类库外,还把每个加载的类放到了一个保护域(protection domain)中,保护域对类的活动范围也有一个定义。
分享到:
评论

相关推荐

    JVM类加载器 test

    JVM类加载器 test

    JVM类加载器说明文档

    介绍Java类的加载机制,对于深入理解Java的深层原理很有帮助

    wanglijun93#AndroidNote#JVM类加载器1

    第一阶段要验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理 第二阶段是对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言

    jvm类加载器基础解析

    主要介绍了jvm类加载器基础解析,具有一定借鉴价值,需要的朋友可以参考下

    深入Java虚拟机_002_深入详解JVM之类加载器深度剖析、根、扩展及系统类加载器

    深入Java虚拟机_002_深入详解JVM之类加载器深度剖析、根、扩展及系统类加载器

    JVM类加载跟踪器

    JVM类加载跟踪器,用于排查jar包冲突、类冲突、类版本冲突、NoClassDefFoundError、ClassNotFoundException 等等类加载相关问题的辅助工具

    【JVM】类加载器与双亲委派模型

    内嵌在JVM内核中的加载器,由C++语言编写(因此也不会继承ClassLoader),是类加载器层次中最顶层的加载器。用于加载java的核心类库,即加载jre/lib/rt.jar里所有的class。由于启动类加载器涉及到虚拟机本

    indexed-classloader:一个自定义的 JVM 类加载器,它索引类路径元素以获得更快的类资源位置

    索引类加载器一个自定义的 JVM 类加载器,它为类路径元素编制索引,以便更快地定位类/资源。 构建: ./make-jar.sh 要使用,将indexed-classpath.jar添加到类路径并设置-Djava.system.class.loader=org.pantsbuild....

    JAVA-JVM-01类加载机制

    java中JVM类加载器和双亲委派机制剖析,类加载示例、加载器示例、自定义一个类加载器示例;Tomcat自定义加载器详解

    Java虚拟机JVM类加载初始化

    由Java虚拟机自带的默认加载器(根加载器、扩展加载器、系统加载器)所加载的类在JVM生命周期中始终不被卸载。所以这些类的Class对象(我称其为实例的模板对象)始终能被触及!而由用户自定义的类加载器所加载的类会...

    轻松搞定jvm类加载器

    而**当我们需要用到某个类时,jvm将会加载它,并在内存中创建对应的class对象,这个过程称之为类的加载。**过程如下: 类的加载、连接、初始化 1. 加载 通过类的包名和雷鸣查找到此类的字节码文件,将xx.class文件...

    Java学习笔记

    类加载器 ClassLoader 字节码校验器 解释执行器 (翻译)逐行的解释执行代码 2.安全 健壮 3.面向对象 面向过程: 程序:函数+变量 (算法+数据结构) 面向对象: 如:SmallTalk 程序:对象和对象相互之间的“通讯” ...

    jvm类加载器.pdf

    jvm原理(面试用)

    JVM核心机制_深入类加载器_层次结构(三种类加载器)_代理加载模式_双亲委派机制_类加载器

    JVM核心机制_深入类加载器_层次结构(三种类加载器)_代理加载模式_双亲委派机制

    JVM 工作原理

    JVM的生命周期 JVM的体系结构 JVM类加载器 JVM执行引擎 JVM运行时数据区 JVM垃圾回收 问题

    类加载器(java)

    当JVM(Java虚拟机)启动时,会形成由三个类加载器组成的初始类加载器层次结构,理解类加载器:J2EE 环境下的 log4j.files

    JVM:类加载器子系统.pdf

    总结了类加载器子系统相关的内容,主要包括类加载器子系统的作用、ClassLoader角色、加载的过程、双亲委派机制以及沙箱安全机制等内容

    JVM、Tomcat、OSGI等类加载器整理文档

    这里将JVM、OSGI、Tomcat以及OSGI和Web服务器整合平台的类加载器做了详细的说明和分析,能让你对类加载器的做一个较为系统的了解。

    掌握Java类加载器

    类加载器从源文件(通常是.class 或 .jar文件)获得不依赖平台的字节码,然后将它们加载到JVM内存空间,所以它们能被解释和执行。默认状态下,应用程序的每个类由java.lang.ClassLoader加载。因为它可以被继承,所以...

Global site tag (gtag.js) - Google Analytics