java分布式对象(RMI+部署使用RMI的程序)

【0】README

1)本文文字转自 core java volume 2, 旨在学习 java 分布式对象的相关知识;
2) RMI 的实例程序为原创;
3) RMI部署步骤的测试用例,参见 http://blog.csdn.net/pacosonswjtu/article/details/50705258


【1】知识背景

1)每过一段时间, 程序员社区就开始考虑“无所不在的对象”作为所有问题的解决之道;
2) 当一台计算机上的某个对象需要调用另一台计算机上的某个对象时, 他就会发送一个包含这个请求的详细信息的网络消息;
3)一旦该远程对象得到了客户端请求的东西, 就将他发送给 客户端;
4)在本章,我们将聚焦在Java的分布式编程技术上,特别是用于两个Java虚拟机(可以运行在不同的计算机上)之间通信的远程方法调用(RMI)协议。
5)RMI: Remote Method Invocation == 远程方法调用协议;


【2】客户与服务器的角色

1)所有分布式编程技术的基本思想都很简单:客户计算机产生一个请求,然后将这个请求经由网络发送到服务器。服务器处理这个请求,并发送回一个针对该客户端的响应,供客户端进行分析。图11-1展示了这个过程。
这里写图片描述

2)problem+solution:

  • 2.1)problem:我们真正想要的是这样一种机制,客户端程序员以常规的方式进行方法调用,而无需操心数据在网络上传输或者解析响应之类的问题。
  • 2.2)solution:解决的办法是,在客户端为远程对象安装一个代理(proxy)。(干货——引入代理的概念)

3)代理: 是位于客户端虚拟机中的一个对象,它对于客户端程序来说,看起来就像是要访问的远程对象一样。客户调用此代理,进行常规的方法调用。而客户端代理负责与服务器进行联系。
4)problem+solution:

  • 4.1)problem:实现服务的程序员也不希望因与客户端之间的通信而被绊住。
  • 4.2)solution:解决方法是在服务器端安装第二个代理对象。该服务器代理与客户端代理进行通信,并且它将以常规方式调用服务器对象上的方法(参见图11-2)。
    这里写图片描述

5)代理之间是如何通信的呢?这要看以什么技术来实现它们。通常有三种选择(options): (干货——代理间的通信技术)

  • o1) CORBA,通用对象请求代理架构: 支持任何编程语言编写的对象之间的方法调用。CORBA使用Internet Inter-ORB协议(IIOP)支持对象间的通信。
  • o2) Web服务架构是一个协议集,有时统一描述为WS-*。它也独立于编程语言的,不过它使用基于XML的通信格式。用于传输对象的格式则是简单对象访问协议(SOAP)。
  • o3) RMI,Java的远程方法调用技术: 支持Java的分布式对象之间的方法调用。 (干货——引入RMI)

5.1)与RMI不同,CORBA与SOAP都是完全独立于语言的。客户端与服务器程序可以由C、C++、Java或者其他语言编写。
5.2) Sun 开发了一个更简单的机制, 称为远程方法调用-RMI: 专门针对java 应用之间的通信;


【3】远程方法调用(RMI)

1) 分布式计算的关键是远程方法调用。 在一台机器(称为客户端)上的某些代码希望调用在另一台机器(远程对象)上的某个对象的一个方法。要实现这一点,方法的参数必须以某种方式传递到另一台机器上,而服务器必须得到通知,去定位远程对象并执行要调用的方法,并且必须将返回值传递回去。(干货——分布式计算的关键是远程方法调用)


【3.1】存根与参数编组

1)存根: 当客户代码要在远程对象上调用一个远程方法时,实际上调用的是代理对象上的一个普通的方法,我们称此代理对象为存根(stub)。 (干货—— 存根是client 上的 agent object)

  • 1.1)看个荔枝:
    Warehouse centralWarehouse = get stub object;
    double price = centralWarehouse.getPrice(“Blackwell Toaster”);
  • 1.2)存根位于客户端机器上,而非服务器上。它知道如何通过网络与服务器联系。
  • 1.3)存根将远程方法所需的参数打包成一组字节。
  • 1.4)参数编组:对参数编码的过程称作参数编组(parameter marshalling),参数编组的目的是将参数转换成适合在虚拟机之间进行传递的格式。在RMI协议中,对象是使用序列化机制进行编码的,第1章描述了这种机制。在SOAP协议中,对象被编码为XML。 (干货——参数编组定义)

2)总的来说,客户端的存根方法构造了一个信息块,它由以下几部分组成(parts):

  • p1)被使用的远程对象的标识符;
  • p2)被调用的方法的描述;
  • p3)编组后的参数;

3)然后,存根将此信息发送给服务器。在服务器一端,接收对象执行以下动作(actions):

  • a1)定位要调用的远程对象;
  • a2)调用所需的方法,并传递客户端提供的参数;
  • a3)捕获返回值或该调用产生的异常;
  • a4)将返回值编组,打包送回给客户端存根。

4) 反编组:客户端存根对来自服务器端的返回值或异常进行反编组,就成为了调用存根的返回值。如果远程方法抛出了一个异常,那么存根就在客户端发起调用的处理空间中重新抛出该异常。图11-3展示了一次远程方法调用的信息流。
这里写图片描述

Attention) 这个过程显然很复杂,不过好消息是,这一切都是完全自动的,而且在很大程度上,它对程序员是透明性。


【4】RMI 编程模型

【4.1 接口实现】

1) 如何实现和启动服务器与客户端程序。 (干货——如何实现和启动服务器与客户端程序)

step1)远程对象的能力是由在客户端和服务器之间共享的接口所表示的。例如,以下程序的接口描述了远程仓库对象所提供的服务:

public interface Warehouse extends Remote
{double getPrice(String description) throws RemoteException;
}

对以上代码的分析(Analysis):

  • A1)远程对象的接口必须扩展Remote接口,它位于java.rmi包中。
  • A2)接口中的所有方法还必须声明抛出RemoteException异常,这是因为远程方法调用与生俱来就缺乏本地调用的可靠性,远程调用总是存在失败的可能。

step2) 接下来,在服务器端,必须提供这样的类,它真正实现了在远程接口中声明的工作。

public class WarehouseImpl extends UnicastRemoteObject implements Warehouse
{public WarehouseImpl() throws RemoteException{prices = new HashMap<String, Double>();prices.put("Blackwell Toaster", 24.95);prices.put("ZapXpress Microwave Oven", 49.95);}public double getPrice(String description) throws RemoteException{Double price = prices.get(description);return price == null ? 0 : price;}private Map<String, Double> prices;
}

Attention) UnicastRemoteObject类 :你可以看出这个类是远程方法调用的目标,因为它继承自UnicastRemoteObject,这个类的构造器使得它的对象可供远程访问。
2)problem+solution:

  • 2.1)problem:有时候可能不希望服务器类继承UnicastRemoteObject,也许是因为实现类已经继承了其他的类。
  • 2.2)solution:在这种情况下,读者需要亲自初始化远程对象,并将它们传给静态的exportObject方法。如果不继承UnicastRemoteObject,可以在远程对象的构造器中像下面这样调用exportObject方法。
    UnicastRemoteObject.exportObject(this, 0); // 第二个参数是0,表明任意合适的端口都可用来监听客户端连接。

Attention) Unicast这个术语是指我们是通过产生对单一的IP地址和端口的调用来定位远程对象的这一事实。这是Java SE中唯一支持的机制。更复杂的分布式对象系统(诸如JINI)会考虑到对在多个不同的服务器上的远程对象的”Multicast”查找。 (干货——这里提到了JINI)

intro to jini ( from http://baike.baidu.com/link?url=2uT-UgPQerl5Xze13Xqyg0e9eVTH5SOI6ucWnFw_nMKHw8754Lc1H_eM94gxiM7U0U9FUttdQd1yZCiBeYvVlK)
Jini(Java Intelligent Network Infrastructure)是Sun公司的研究与开发项目,它能极大扩展Java技术的能力。Jini技术可使范围广泛的多种硬件和软件—即可与网络相连的任何实体—能够自主联网。
Jini可以使人们极其简单地使用网络设备和网络服务,就象今天我们使用电话一样—通过网络拨号即插即用。Jini的目标是最大限度地简化与网络的交互性。


【4.2】RMI注册表

1)problem+solution:

  • 1.1)problem:要访问服务器上的一个远程对象时,客户端首先需要一个本地的存根对象。可是客户端如何对该存根发出请求呢?最普通的方法是调用另一个服务对象上的一个远程方法,以返回值的方式取得存根对象。然而,这就成了先有鸡还是先有蛋的问题。
  • 1.2)solution:第一个远程对象总要通过某种方式进行定位。为此,JDK提供了自举注册服务(bootstrap registry service)。

2)如何注册一个远程对象? (干货——如何注册一个远程对象)
服务器程序使用自举注册服务来注册至少一个远程对象。要注册一个远程对象,需要一个RMI URL和一个对实现对象的引用。RMI的URL以rmi:开头,后接服务器以及一个可选的端口号,接着是远程对象的名字。例如: rmi://localhost:99/central_warehouse
3)默认情况下,主机名是localhost,端口为1099。 服务器告诉注册表在给定位置将该对象关联或”绑定”到这个名字。

  • 3.1)下面的代码将一个WarehouseImpl对象注册到了同一个服务器上的RMI注册表中: (干货——绑定远程对象到server上的RMI注册表中)
    WarehouseImpl centralWarehouse = new WarehouseImpl();
    Context namingContext = new InitialContext();
    namingContext.bind(“rmi:central_warehouse”, centralWarehouse);

  • 3.2) 看个荔枝:下面的程序只是构造并注册了一个WarehouseImpl对象
    这里写图片描述

Attention) 基于安全原因,一个应用只有当它与注册表运行在同一个服务器时,该应用才可以绑定、取消绑定,或重绑定注册对象的引用。
4)客户端可以通过下面的调用枚举所有注册过的RMI对象: (干货——注意是client 端枚举 出 server 端 注册过的RMI对象)

Enumeration<NameClassPair> e = namingContext.list("rmi://regserver.mycompany.com")

5)NameClassPair是一个助手类: 它包含绑定对象的名字和该对象所属类的名字。

  • 5.1)看个荔枝: 例如,下面的代码可以显示所有注册对象的名字:
    while (e.hasMoreElements())
    System.out.println(e.nextElement().getName());

6)客户端可以通过下面的方式,来指定服务器和远程对象的名字,以此获得访问远程对象所需的存根: (干货——client端获得存根)

String url = "rmi://regserver.mycompany.com/central_warehouse";
Warehouse centralWarehouse = (Warehouse) namingContext.lookup(url); 

Attention) 在一个全局注册表中,想保持一个名字的惟一性非常困难,因此不应该将此技术作为定位服务器端对象的一般方法。相反,自举服务只应该用来注册非常少的远程对象。然后使用这些对象来定位其他的对象。 (干货——自举服务的局限性)
7) 代码11-4展示了客户端如何获得远程仓库对象的存根,并调用远程的getPrice方法。
这里写图片描述
这里写图片描述


【4.3】部署程序(you can also refer to http://www.cnblogs.com/leslies2/archive/2011/05/20/2051844.html)

0)部署前的准备

  • 0.1)创建两个目录, 分别存放用于启动server 和 client 的类:

    server/
    WarehouseServer.class
    Warehouse.class
    WarehouseImpl.class
    client/
    WarehouseClient.class
    Warehouse.class

  • 0.2)当部署RMI 应用时, 通常需要动态地将类交付给运行程序,其中一个例子就是RMI注册表。请记住注册表的一个实例要服务许多不同的RMI应用。RMI注册表需要有权限访问注册的服务接口的类文件,但是,当注册表启动时,无法预测将来会产生的所有注册请求。因此,RMI 注册表会动态地加载之前从未遇到过的所有远程接口的类文件;

  • 0.3)动态交付的类文件是通过标准的web server发布的。在我们所举的case中, server程序 需要使用 Warehouse.class 文件 对于 RMI 注册表来说是可以获得的,因此将这个文件放到了第三个称为download 目录中的:

    download/
    Warehouse.class

  • 0.4)下面,我们用 web server 来访问这个目录中的内容(NanoHTTPD web server)

1)当应用被部署时,服务器、RMI注册表、Web服务器和客户端可以定位到四台不同的计算机上,参见图11-5。但是,出于测试的目的,我们将只使用一台计算机。
这里写图片描述

Attention) 由于安全的原因,作为JDK一部分的rmiregistry服务只允许来自同一台主机的绑定调用。也就是说,服务器和rmiregistry进程需要定位在同一台计算机上。但是,RMI架构允许更通用的支持多台服务器的RMI注册表实现。 (干货——基于安全原因,服务器和rmiregistry进程需要定位在同一台计算机上)
2)测试远程方法调用:

  • step1)打开一个新的控制台窗口,转到download目录,然后将NanoHTTPD.java(NanoHTTPD web 服务器)复制到这个目录中。使用下面的命令来编译该源文件并启动这个web服务器: java NanoHTTPD 8080
    这里写图片描述

  • step2)打开另一个控制台窗口,转到不包含任何类文件的某个目录,并启动RMI注册表:rmiregistry
    这里写图片描述

Attention)

  • A1)在启动RMI注册表之前,请确保CLASSPATH环境变量没有进行任何设置,并仔细检查当前目录是否确实不包含任何类文件。否则,RMI注册表可能会找到一些假冒的类文件,这使得注册表需要从另一个不同的来源下载额外的类文件时,产生混淆。
  • A2)简单地讲,每个存根对象都有一个代码基项,指出了它是从何处加载的。这个代码基被用来加载它所依赖的类。如果RMI注册表在本地找到了这样的类,那么它的代码基就会被设置为错误的值。
  • A3)推荐在server 程序中通过代码注册通讯端口和注册通讯路径 (干货——不推荐使用 rmiregistry命令行)

    // 注册通讯端口
    LocateRegistry.createRegistry(1099);
    // 注册通讯路径
    Naming.rebind(“rmi://localhost:1099/warehouseService”, warehouseService);

  • step3)现在已经准备好启动服务器了。打开第三个控制台窗口,转到server目录,并执行下面的命令:

    java -Djava.rmi.server.codebase=http://localhost:8080/ WarehouseServer // java.rmi.server.codebase属性指出了服务类文件的URL。服务器程序将这个URL传递给RMI注册表。
    这里写图片描述

  • Warning) 确保代码基URL以斜杠”/”结尾非常重要。
  • step4)最后,打开第四个控制台窗口,转到client目录,运行:

  • 你将会看到一条短消息,表示运行方法被成功调用, 参见图11-6所示;
    这里写图片描述


【4.4】记录 RMI 活动的日志

1) 如果用下面的选项启动服务器:

-Djava.rmi.server.logCalls=true WarehouseServer & // 那么服务器会在其控制台上记录所有的远程方法调用到日志中。
java -Djava.rmi.server.logCalls=true -Djava.rmi.server.codebase=http://localhost:8080/ com.corejava.chapter11.server.WarehouseServer

这里写图片描述

2) 如果想查看额外的日志信息,就必须用标准的Java日志API配置日志记录器。

  • 2.1) 可以用下面的内容创建一个logging.properties文件。

    handlers=java.util.logging.ConsoleHandler
    sun.rmi.loader.level=FINE
    java.util.logging.ConsoleHandler.level=FINE
    java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter

  • 2.2)我们可以对设置进行调整,方法是为每一个记录器设置单独的等级而不是设置全局等级。例如,要跟踪类的加载行为,可以设置为:

    sun.rmi.loader.level=FINE

  • 2.3)用以下选项启动RMI注册表

    -Djava.util.logging.config.file=directory/logging.properties

  • 2.4)用以下选项启动客户端与服务器

    -Djava.util.logging.config.file=directory/logging.properties

  • 2.5)表11-1 列出了所有的RMI 日志记录器:
    这里写图片描述
    这里写图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/331406.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 创建uri_使用UriBuilder快速创建URI

java 创建uri如果您有权访问JAX-RS API和项目中的实现&#xff08;很多&#xff09;&#xff0c;则可以使用JAX-RS的UriBuilder通过使用可解析占位符的构建器模式方便地创建URI。 看下面的例子&#xff1a; String host System.getProperty( "host" , "localh…

Tomcat 服务自动启动

一、配置/etc/rc.local rc.local是linux启动init之后执行的脚本。 sudo vi /etc/rc.local 添加如下一行 /home/myuser/software/apache-tomcat-7.0.29/bin/startup.sh&#xff08;脚本绝对路径&#xff09; 二、sysv-rc-conf 工具配置 1、安装 sysv-rc-conf sudo apt-get …

java分布式对象RMI应用测试用例

【0】README 0.1&#xff09;本文旨在对http://blog.csdn.net/PacosonSWJTU/article/details/50705192 中的代码进行实践&#xff08;如何部署一个使用RMI框架的程序以进行远程调用&#xff09;&#xff1b; 0.2&#xff09; for complete source code, please visit https…

neo4j 迁移_在Kubernetes中迁移Neo4j图模式

neo4j 迁移在零停机时间下运行企业应用程序时&#xff0c;我们需要能够执行数据库架构迁移而又不中断活动用户。 这不仅对于关系数据库很重要&#xff0c;而且对于诸如Neo4J之类的图数据库也很重要&#xff0c;后者不会在write上强制执行架构。 但是&#xff0c;重构图形并使图…

Windows访问Linux的Tomcat,显示无法连接

一、端口占用 先查看tomcat下的logs日志文件&#xff0c;如果现实地址已被占用&#xff0c;则需重新修改端口。 tomcat默认启动的是8080&#xff0c;如果你想修改为80&#xff0c;则需要修改server.xml文件:vim $CATALINA_HOME/conf/server.xml #如果没有配置$CATALINA_HOME&am…

java分布式对象——远程方法中的参数和返回值+远程对象激活

【0】README 1&#xff09;本文文字描述转自 core java volume 2&#xff0c; 旨在学习 java分布式对象——远程方法中的参数和返回值远程对象激活 的相关知识&#xff1b; 【1】远程方法中的参数和返回值 1&#xff09; 在开始进行远程方法调用时&#xff0c;调用参数需要从…

wcf:rest_REST:管理多对多关系

wcf:rest介绍 管理多个资源之间的关系可能是RESTful API的重要组成部分。 在这篇文章中&#xff0c;我们将看到使用REST API可以管理多对多关系。 我们以一个简单的用户 / 组关系为例。 假设用户和组是两个单独的资源&#xff08;例如/ users和/ groups &#xff09;&#xff…

java安全——类加载器+字节码校验+安全管理器与访问权限

【0】README 0.1&#xff09;本文文字描述转自 core java volume 2&#xff0c;旨在学习 java安全 的相关知识&#xff1b; 【1】类加载器 1&#xff09;java 技术提供了以下3种确保安全的机制&#xff08;mechanism&#xff09;&#xff1a; m1&#xff09;语言设计特性&am…

Tomcat的web项目部署方式

一、host配置Context 在tomcat中的conf目录中&#xff0c;在server.xml中的&#xff0c;<host/>节点中添加&#xff1a; <Context path"/app" docBase"D:/myeclipse/firstapp/WebRoot" debug"0" privileged"true" reloadab…

java.rmi.UnmarshalException:errorunmarshalling return; java.lang.ClassNotFoundException的解决方法

1&#xff09;problem 出现 java.rmi.UnmarshalException: error unmarshalling return; nested exception is: java.lang.ClassNotFoundException 异常的原因是&#xff0c;在命令行执行 rmiregistry&#xff0c;并没有指定好 绑定时查找的类文件的路径。 …

javafx 图标_JavaFX技巧32:需要图标吗? 使用Ikonli!

javafx 图标动机 自2013年以来&#xff0c;我一直在编写JavaFX应用程序和库的代码&#xff0c;它们的共同点是&#xff0c;我需要找到可以用于它们的良好图标/图形。 作为前Swing开发人员&#xff0c;我首先使用图像文件&#xff0c;GIF或PNG。 通常&#xff0c;我会从IconExpe…

java安全 ——JAAS(Java 认证和授权服务)开发指南

以下内容转自&#xff1a; http://lyb520320.iteye.com/blog/720478【0】README1&#xff09;本文翻译自&#xff1a;http://java.sun.com/developer/technicalArticles/Security/jaasv2/2&#xff09;传统的JAVA安全机制没有提供必要的架构支持传统的认证和授权&#xff1b;在…

aws dynamodb_AWS Lambda将数据保存在DynamoDB中

aws dynamodb在本教程中&#xff0c;我们将看到如何使用AWS Lambda将数据保存在Dynamo DB中。 这是必需的步骤&#xff1a; – 在Dynamo数据库中创建一个名为Employee的表 –创建一个AWS Lambda函数&#xff0c;该函数可以使用Dynamo DB中的Employee POJO保存员工的名字和姓…

Tomcat处理一个HTTP请求的过程

一、Tomcat的组成 &#xff08;1&#xff09;Server服务器元素代表整个catalina servlet容器。是单例模式。 &#xff08;2&#xff09;ServiceService是这样一个集合&#xff1a;它由一个或者多个Connector组成&#xff0c;以及一个Engine&#xff0c;负责处理所有Connector所…

java安全——数字签名+代码签名

【0】README1&#xff09;本文文字描述转自 core java volume 2, 旨在学习 java安全——数字签名 的基础知识&#xff1b;2&#xff09;本文实践内容以及截图笔记均为原创&#xff1b;3&#xff09;如果要给予applet更多的信赖&#xff0c;你必须知道下面两件事&#xff1a; 3.…

//rest风格写_REST /使用提要发布事件

//rest风格写处理事件 当使用多个解耦的服务时&#xff08;例如&#xff0c;在微服务体系结构中 &#xff09;&#xff0c;很有可能需要一种方法来将某种域事件从一个服务发布到一个或多个其他服务。 许多广泛采用的解决方案依赖于单独的基础结构来解决此问题&#xff08;例如…

Java IO总结

一、IO的类型 面向字节的流&#xff0c;面向字符的流二、面向字节的流 &#xff08;1&#xff09;InputStream FileInputStream FilterInputStream -BufferedInputStream -DataInputStream -PushbackInputStream 回退流 unread() ObjectInputStream PipedInputSt…

java安全——加密

【0】README1&#xff09;本文文字描述转自 core java volume 2&#xff0c;旨在学习 java安全——加密 的基础知识&#xff1b;2&#xff09;java 安全性的第二个重要方面是加密。3&#xff09;认证对于代码签名已足够了-没必要将代码隐藏起来。但是&#xff0c;当applet或者应…

java 异常 最佳实践_处理Java异常的10种最佳实践

java 异常 最佳实践在本文中&#xff0c;我们将看到处理Java异常的最佳实践。 用Java处理异常不是一件容易的事&#xff0c;因为新手很难理解&#xff0c;甚至专业的开发人员也可能浪费时间讨论应该抛出或处理哪些Java异常。 因此&#xff0c;最大的开发公司对如何使用它们有一…

Java NIO总结

一、NIO NIO是new IO&#xff0c;也是非阻塞IO。有Channel、Selector、Buffer、Pipe、FileLock等类。 Buffer在java.nio包 Channel、Selector、Pipe、FileLock等在java.nio.channels包 二、Channel通道 设置非阻塞configureBlocking(false); 注册选择器register(selector,…