RMI动态下载类分析

 

部署一个分布式应用可能会很困难,系统即使只运行其中的一部分,也必须安装所有的相关部分。对于一个局域网来说,这是很消耗时间的,虽然不会很困难。然而,当部署一个大规模应用且更新频繁的时候,部署过程会困难的多。动态下载是集成在RMI中的一项技术,试图使这个应用容易些。

一:应用遇到的困难

部署一个应用需要一下步骤:

       1)配置服务器

       2)向名字服务路径增加stub类和其他相关的类和对象

       3)如果一个重新部署和第一次的部署完全相反,那么你可能会重启名字服务并且重新注册

       4)在每一个客户机上安装和配置应用

       简单来说,部署一个web应用不需要改变客户端或者名字服务。取而代之的是,当一个web浏览器下载一个包含applet标签的web页面时,应用只需更少时间而且更容易正确执行。然而,每次你需要更新或者重新部署,不同点变的越来越大。好消息就是,动态下载允许RMI应用动态从http后者ftp下载类定义的字节码。

二:ClassLoader原理

       Java虚拟机下载有效独立的类,通过使用classloader

1:动态链接

每个java源代码被编译为.class文件,每一个.class文件包含了一个单独类的字节码。每一个java类单独编译,运行的时候动态链接。大多数传统编程语言使用的是静态连接模型。 为了生成一个可执行的应用,源代码必须编译,并且所有引用的必须立即解决 。也就是说,各个独立的应用部件必须链接在一起。动态链接尽可能的推迟组合过程。对于运行一个java应用,很有可能,一些引用从来都没有实际用过,因为引用方法没有被调用。

       刚开始,这个看起来没有什么特别。C++程序员经常那个在大脑中有一个hard time。但是如果你想一下,为了使得java正常工作,一些动态链接的的形式很有必要,考虑下面典型应用:

       1)用JDK1.2linux机器写了一个applet

       2)从Macintosh下载一个web页面,appletMRJ内部使用JDK1.1.6执行应用。

       这些应用场景对C++来说是不可能的,链接必须推迟到直到执行。不幸的是,当应用部分更新的时候,动态链接也会出问题。如果你改变了一些.class文件,你可能有两个不能链接一起的文件。

RMI采用JVM中采用动态类型加载方式,所以概念上只有当一个类型被应用到时,虚拟机才会加载它。比如,假设类C引用了类D,只有当虚拟机执行到C中引用D的语句时才会去加载D 其中有Defining Class Loader Initiating Class LoaderDefining class loader是指真正执行加载某个类的动作的那个类加载器实例。在虚拟机中,一个类型C是由其类型名和定义它的那个defining class loader来唯一标识的,即C=<N, L>Iniating class loader是指发起这个加载动作的类加载器实例。比如在前面的例子中,虚拟机发现C引用D时,就把Cdefining class loader作为Dinitiating class loader。至于D最终是由谁定义的,则要由class loader的代理机制来决定。

2:常见Class Loader以及其关系

Bootstrap class loader:虚拟机运行时必须要用到的类的加载器,比如java.*。它通常是在虚拟机种用本地代码实现,在系统中用null表示。

Extension class loader:负责加载Java环境中安装的可选包(optional package)中的类。

Application class loader:负责加载CLASSPATH上的类。有时候也称为system class loaderJava程序可以通过调用java.lang.getSystemClassLoader()获得它的引用。

Class loader之间有两种层次关系:继承关系和代理(delegation)关系。

bootstrap class loader之外的所有其它class loader都是用Java语言来实现的,所以它们之间自然有继承关系。Java API里面定义的类的继承关系如下:java.net.URLClassLoader --> java.security.SecureClassLoader --> java.lang.ClassLoader --> java.lang.Object

代理关系是class loader实例之间的动态关系。在创建一个class loader实例时可以给其构造函数传递一个parent参数,这样该parent就成了新创建的class loader在代理层次上的父节点。这个层次树的根节点就是bootstrap class loader实例。Java程序可以通过调用class loader实例的getParent()方法来获取其父节点。比如在JDK1.5中运行HelloWorld程序时class loader的代理继承关系如下:sun.misc.Launcher$AppClassLoader --> sun.misc.Launcher$ExtClassLoader --> null bootstrap class loader)。

3:代理机制

当一个class loader收到加载某个类的请求时,它按照下面的流程处理:

1)查找这个类是不是已经被自己加载过,如果没有则进行下一步;

2)请求代理层次中的父加载器加载这个类;

3)如果父加载器无法加载这个类(抛回异常),则尝试自己加载这个类。如果能够加载,则定义该类,否则抛出异常。

所以在代理层次结构上的子节点永远只加载父节点(及其祖先节点)所不能加载的类,这样可以保证类始终被合适的class loader加载,比如rt.jar中的类永远被bootstrap class loader加载。

4:类的下载

       1)当JVM第一次启动,一个独立的classloader类,也就是作为引导程序,被创建。这个classloader负责相爱在和创建在JVM内部使用的类。

       2)一个应用可以创建更多的classloader,每一个classloader,除了引导程序classloader,都有一个父classloaderclassloader集合组成了一个树形结构,其中引导类classloader是根结点。

       3)当需要一个类对象,JVM寻找一个合适的classloader并使用loadClass()来获得类对象。classloader首先想其父节点请求类,如果父节点没有运行,则自己创建一个。

       这个想法的背后是,classloader是一个方式来划分类集合以及其定义。例如,如果两个兄弟classloader被要求同样的类,则这个类被初始化两次。

       classloader在两个应用很有用。第一个,当你想从一个不标准的资源下载类对象。引导classloader试图利用CLASSPATH变量从文件系统下载类。它希望一个类的包和名字映射到一个包含类字节码的.class文件。如果你想从不同资源下载类,你需要安装另一个classloader,例如java.net.URLClassLoader.第二个,相同类的不同版本在同一时间运行。因为classloader只是检查其父节点,而不检查其兄弟节点,来检查类是否被下载,所以所以有可能同一个类的不同版本被下载。

5:动态下载的实现

       RMI动态下载基于两个思想:

       1)如果一个对象被序列化并且通过线路传送,需要的类定义可能在另一边可获得。

       2)在序列化对喜爱那个内部自动从URLS下载类,这样使得特殊目的的classloader,例如URLClassLoader类,在需要并行化一个对象的时候通过线路自动下载类。

RMI反序列化思想

       1)一个实例通过线路发送。作为一部分对象序列化信息,所有类定义相关的信息被通过线路发送。每一个类还有URL的字符串序列。

       2)反序列化机制为刚描述的类寻找合适的ClassLoader。之所以可以这样是因为,RMI运行时保持了一个URLCassLoader实例集合的索引。

       3)如果类存在,URLClassLoader的实例就返回他们。如果类不存在则URLClassLoader下载他们。

       因为ClassLoader类在试图下载他们之前先向其父节点请求,第一个试图下载的会从文件系统下载。如果引导ClassLoader不能下载类,则类下载仅仅使用URLs

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值