参考:http://blog.csdn.net/smcwwh/article/details/7080997

1.客户与服务器的角色

所有分布式编程技术的基本思想都很简单:客户计算机产生一个请求,然后将这个请求通过网络发送到服务器。服务器处理这个请求,并发送回一个针对客户端的响应,供客户端进行分析。

这些请求和响应并不是在 Web 应用程序中看到的请求和响应。这里的客户端并非是 Web 浏览器,它可以是执行具有任意复杂度的业务规则的任何应用程序。客户端应用程序可以与人类之间进行交互,但也可以没有这种交互。

我们真正想要的是这样一种机制,客户端程序员以常规的方式进行方法调用,而无需操心将数据发送到网络上或者解析响应之类的问题。解决的办法是,在客户端为远程对象安装一个代理。代理位于客户端虚拟机中的换一个对象,它对于客户端程序来说,看起来就像是要访问的远程对象一样。客户调用此代理时,只需进行常规的方法调用。而客户端代理则负责使用网络协议与服务器进行联系。同样,实现服务的程序员也不希望因与客户端之间的通信被绊住。解决方法是在服务器端安装第二个代理对象。该服务器代理与客户端代理进行通信,并且它将以常规方式调用服务器对象上的方法。

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

CORBA:通用对象请求代理架构,支持任何编程语言编写的对象之间的方法调用。CORBA 使用二进制的 Internet Inter-ORB 协议(IIOP)来实现对象间的通信。

Web 服务架构的一个协议集,有时统一描述为 WS-*:它也是独立于编程语言的,不过它使用基于 XML 的通信格式。用于传输对象的格式则是简单的对象访问协议(SOAP)。

RMI:Java 的远程方法调用技术,支持 Java 分布式对象之间的方法调用。

CORBA 与 SOAP 都是完全独立于语言的。你只需提供一个接口描述,以说明你的对象的方法的签名以及能够处理的数据类型。该接口描述的是用一种特殊的语言编写的,对于 CORBA 来说是接口定义语言(IDL),对于 Web 服务而言则是 Web 服务描述语言(WSDL)。

2.远程方法调用

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

客户端/服务器 这一术语用法只适用于单个的方法调用。调用远程方法的计算机对于这个调用来说是客户端,而处理这个调用的对象的宿主计算机对于这个调用来说是服务器。在某些情况下这两个角色完全有可能会颠倒过来,前一个调用的服务器在调用驻留在另一台计算机上的对象的某个远程方法时,它自己就变成了客户端。

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

存根位于客户端机器上,而非服务器上,它知道如何通过网络与服务器联系。存根会将远程方法所需的参数打包成一组字节。对参数编码的过程称作参数编组(parameter marshalling),参数编组的目的是将参数转换成适合在虚拟机之间进行传递的格式。在 RMI 协议中,对象是使用序列化机制进行编码的。在 SOAP 协议中,对象被编码为 XML。

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

被使用的远程对象的标识符。

被调用的方法的描述。

编组后的参数。

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

定位要调用的远程对象。

调用所需的方法,并传递客户端提供的参数。

捕获返回值或该调用产生的异常。

将返回值编组,打包送回给客户端存根。

客户端存根对来自服务器端的返回值或异常进行反编组,其结果就成为调用存根的返回值。如果远程方法抛出了一个异常,那么存根就在客户端的虚拟机中重新抛出该异常。

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

实现远程对象和获取客户端存根的细节有赖于分布式对象采用的技术。

3.RMI 编程模型

远程对象的能力是由在客户端和服务端之间共享的接口所表示的。

远程对象的接口必须扩展 Remote 接口,它位于 java.rmi 包中。接口中的所有方法还必须声明抛出 RemoteException 异常,这是因为远程方法调用与生俱来就缺乏本地调用的可靠性,远程调用总是存在失败的可能。客户端代码必须时刻装备好处理这些问题。基于这些原因,Java 编程语言要求每一次远程方法调用都必须捕获 RemoteException,并且指明当调用不成功时应执行的相应的处理操作。

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

通常,远程对象都 继承UnicastRemoteObject类,UnicastRemoteObject 类提供远程对象所需的基本行为。在这个类中提供了支持创建和导出远程对象的一系列方法,一个对象继承UnicastRemoteObject它将获得以下特性:

A、对这种对象的引用至多仅在创建该远程对象的进程生命期内有效

B、使得远程对象既有使用TCP协议通信的能力(Socket)

C、对于客户端与服务器的调用、传参、返回值等操作使用流的方式来处理

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

要访问服务器上的一个远程对象时,客户端首先需要一个本地的存根对象。可是客户端如何请求得到该存根呢?最普通的方法是调用另一个服务对象上的一个远程方法,以返回值的方式取得存根对象。

第一个远程对象总要通过某种方式进行定位。为此,JDK 提供了自举注册服务。服务器程序应该使用自举注册服务来注册至少一个远程对象。要注册一个远程对象,需要一个 RMI URL 和一个对实现对象的引用。RMI URL 以 rmi: 开头,后接服务器以及一个可选的接口号,接着是远程对象的(希望是)唯一的名字。

例如:rmi://regserver.mycompany.com:99/central_warehouse

默认情况下,主机名是 localhost,端口号为 1099。服务器告诉注册表在给定位置将这个名字关联或“绑定”到该对象。

基于安全原因,一个应用只有当它与注册表运行在同一个服务器时,该应用才可以绑定、取消绑定,或重新绑定注册对象的引用。这可以防止有恶意的客户端修改注册表信息。但是,任何客户端都可以查找对象。

在一个全局的注册表中,想保持一个名字的唯一性非常困难,因此不应该将此技术作为定位服务器端对象的通用方法。相反,自举服务只应该用来注册非常少的远程对象。然后使用这些对象来定位其他的对象。

 package rmi;

 import java.rmi.Remote;
import java.rmi.RemoteException; public interface Warehouse extends Remote { double getPrice(String description) throws RemoteException; }
 package rmi;

 import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.Map; public class WarehouseImpl extends UnicastRemoteObject implements Warehouse { private Map<String, Double> prices; public WarehouseImpl() throws RemoteException {
prices = new HashMap<>();
prices.put("Blackwell Toaster", 24.95);
prices.put("ZapXpress Microwave Oven", 49.95);
} @Override
public double getPrice(String description) throws RemoteException {
// TODO Auto-generated method stub
Double price = prices.get(description);
return prices == null ? 0 : price;
} }
 package rmi;

 import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry; import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException; public class Server { public static void main(String[] args) {
try {
System.out.println("Constructing server implementation ..");
WarehouseImpl centralWarehouse = new WarehouseImpl(); System.out.println("Binding server implementation to registry ..");
Context namingContext = new InitialContext();
LocateRegistry.createRegistry(1099);
namingContext.bind("rmi://localhost:1099/central_warehouse", centralWarehouse); System.out.println("Waiting for invocations from clients ..");
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } }
 package rmi;

 import java.rmi.RemoteException;

 import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException; public class Client { public static void main(String[] args) {
try {
Context context = new InitialContext();
Warehouse warehouse = (Warehouse) context.lookup("rmi://localhost:1099/central_warehouse");
double price = warehouse.getPrice("Blackwell Toaster");
System.out.println(price);
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }

JavaEE--分布式对象的更多相关文章

  1. 三种分布式对象主流技术——COM、Java和COBRA

    既上一遍,看到还有一遍将关于 对象的, 分布式对象, 故摘抄入下: 目前国际上,分布式对象技术有三大流派——COBRA.COM/DCOM和Java.CORBA技术是最早出现的,1991年OMG颁布了C ...

  2. go语言实现分布式对象存储系统之单体对象存储

    对象存储 基本概念 主流存储类型分为三种:块存储.文件存储以及对象存储 NAS(文件存储):Network Attached storage,提供了存储功能和文件系统的网络服务器,客户端可以访问NAS ...

  3. Spring Security 实战干货:分布式对象SharedObject

    1. 前言 在上一篇我们对AuthenticationManager的初始化的细节进行了分析,其中里面有一段代码引起了不少同学的注意: ApplicationContext context = htt ...

  4. 《分布式对象存储》作者手把手教你写 GO 语言单元测试!

    第一部分:如何写Go语言单元测试 Go语言内建了单元测试(Unit Test)框架.这是为了从语言层面规范写UT的方式. Go语言的命名规则会将以_test.go结尾的go文件视作单元测试代码. 当我 ...

  5. Go简易分布式对象存储 合并文件的所有分块为一个文件

    项目 项目地址: https://github.com/Draymonders/cloud 欢迎大家Watch or Star 缘由 由于项目中对大文件进行5MB为一个分块上传(多线程,提升上传效率) ...

  6. Java 对象的串行化(Serialization)

    1.什么是串行化 对象的寿命通常随着生成该对象的程序的终止而终止.有时候,可能需要将对象的状态保存下来,在需要时再将对象恢复.我们把对象的这种能记录自己的状态以便将来再生的能力.叫作对象的持续性(pe ...

  7. WCF分布式开发步步为赢(7):WCF数据契约与序列化

    本节继续学习WCF分布式开发步步为赢(7):WCF数据契约与序列化.数据契约是WCF应用程序开发中一个重要的概念,毫无疑问实现客户端与服务端数据契约的传递中序列化是非常重要的步骤.那么序列化是什么?为 ...

  8. javaEE的十三个技术规范

    java 是一种非常棒的语言,健壮,跨平台运行,屏蔽了具体的平台环境的要求,也就是说只要支持java 虚拟机,就可以运行java程序. 下面,我们一起学习一下J2EE的十三种技术规范. 一.JDBC: ...

  9. Java分布式处理技术(RMI,JDNI)

    http://hedaoyuan.blog.51cto.com/4639772/813702 1.1 RMI的基本概念 1.1.1 什么是RMI RMI(Remote Method Invocatio ...

  10. 从腾讯QQgame高性能服务器集群架构看“分而治之”与“自治”等分布式架构设计原则

    转载:http://space.itpub.net/17007506/viewspace-616852 腾讯QQGame游戏同时在线的玩家数量极其庞大,为了方便组织玩家组队游戏,腾讯设置了大量游戏室( ...

随机推荐

  1. JAVA中序列化和反序列化中的静态成员问题

    关于这个标题的内容是面试笔试中比较常见的考题,大家跟随我的博客一起来学习下这个过程. ? ? JAVA中的序列化和反序列化主要用于: (1)将对象或者异常等写入文件,通过文件交互传输信息: (2)将对 ...

  2. 在登陆退出时候使用Vuex

    1.登陆的时候,在登陆模块请求接口,然后获取一个access_token,获取用户权限.保存到缓存里面. 2.退出的时候,请求退出接口,把缓存里面的access_token清除. 一旦要在登陆里面做一 ...

  3. UVA - 294 Divisors (约数)(数论)

    题意:输入两个整数L,U(1<=L<=U<=109,U-L<=10000),统计区间[L,U]的整数中哪一个的正约数最多.如果有多个,输出最小值. 分析: 1.求一个数的约数, ...

  4. c++ opencv 动态内存

    1.CvMemStorage定义动态内存存储器   内存存储器是一个用来存储诸如序列.轮廓.图形和子划分等动态增长数据结构的底层结构 2.示例 CvMemStorage *mems = cvCreat ...

  5. 洛谷 P1043 数字游戏

    题目传送门 解题思路: 跟石子合并差不多,区间DP(环形),用f[i][j][s]表示从i到j分成s段所能获得的最大答案,枚举断点k,则f[i][j][s] = min(f[i][j][s],f[i] ...

  6. react入门(1)之阮一峰react教程

    阮一峰老师的github地址:React Demos React 入门实例教程 2.ReactDOM.render() // ReactDOM.render() 将模板转化为 HTML 语言 // 参 ...

  7. Maven - 工作原理

    章节 Maven – 简介 Maven – 工作原理 Maven – Repository(存储库) Maven – pom.xml 文件 Maven – 依赖管理 Maven – 构建生命周期.阶段 ...

  8. c++ 正则表达式查找

    C++ 正则表达式的使用 需求: 字符串含有除[0-9a-z]之外的字符,均返回失败! #include<regex> smatch result; string reg_str = &q ...

  9. 编写检测深度模型测试程序python

    参考:https://blog.csdn.net/haoji007/article/details/81035565?utm_source=blogxgwz9 首先从网上下载imagenet训练好的模 ...

  10. JZOJ-2019-11-5 A组

    T1 给定由 n 个点 m 条边组成的无向连通图,保证没有重边和自环. 你需要找出所有边,满足这些边恰好存在于一个简单环中.一个环被称为简单环,当且仅当它包含的所有点都只在这个环中被经过了一次.(即求 ...