发表于: 2017-11-07 22:28:19

1 811


一.今日完成

1.学习整理RMI实现原理

(1)客户与服务器的角色

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

想要的是这样一种机制,客户端程序员以常规的方式进行方法调用,而无需操心数据在网络上传输或者解析响应之类的问题。解决的办法是,在客户端为远程对象安装一个代理(proxy)

实现服务的程序员也不希望因与客户端之间的通信而被绊住。解决方法是在服务器端安装第二个代理对象。该服务器代理与客户端代理进行通信,并且它将以常规方式调用服务器对象上的方法.

代理间的通信技术:

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

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

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

与RMI不同,CORBA与SOAP都是完全独立于语言的。客户端与服务器程序可以由C、C++、Java或者其他语言编写。 


(2)远程方法调用(RMI)

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

1)存根与参数编组

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

i.存根位于客户端机器上,而非服务器上。它知道如何通过网络与服务器联系。

ii.存根将远程方法所需的参数打包成一组字节。

iii.参数编组:对参数编码的过程称作参数编组(parameter marshalling),参数编组的目的是将参数转换成适合在虚拟机之间进行传递的格式。在RMI协议中,对象是使用序列化机制进行编码的。在SOAP协议中,对象被编码为XML。


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

i.被使用的远程对象的标识符;

ii.被调用的方法的描述;

iii.编组后的参数;

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

i.定位要调用的远程对象;

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

iii.捕获返回值或该调用产生的异常;

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

反编组:客户端存根对来自服务器端的返回值或异常进行反编组,就成为了调用存根的返回值。如果远程方法抛出了一个异常,那么存根就在客户端发起调用的处理空间中重新抛出该异常。一次远程方法调用的信息流如下。 

(3)RMI 编程模型

首先建立一个Model层,因为此对象需要现实进行远程传输,所以必须继承Serializable

public  class PersonEntity implements Serializable {
private  int id;
private String name;
private  int age;

public  void setId(int id) {
this.id = id;
}

public  int getId() {
return id;
}

public  void setName(String name) {
this.name = name;
}

public String getName() {
return name;
}

public  void setAge(int age) {
this.age = age;
}

public  int getAge() {
return age;
}
}

2)创建远程接口PersonService,注意远程接口需要继承Remote

public  interface PersonService extends Remote {
public List<PersonEntity> GetList() throws RemoteException;
}

远程对象的接口必须扩展Remote接口,它位于java.rmi包中。

接口中的所有方法还必须声明抛出RemoteException异常,这是因为远程方法调用与生俱来就缺乏本地调用的可靠性,远程调用总是存在失败的可能。


3)建立PersonServiceImpl实现远程接口,注意此为远程对象实现类,需要继承UnicastRemoteObject

public  class PersonServiceImpl extends UnicastRemoteObject implements PersonService {

public PersonServiceImpl() throws RemoteException {
super();
}

@Override
public List<PersonEntity> GetList() throws RemoteException {
System.out.println("Get Person Start!");
List<PersonEntity> personList=new LinkedList<PersonEntity>();

PersonEntity person1=new PersonEntity();
person1.setAge(25);
person1.setId(0);
person1.setName("Leslie");
personList.add(person1);

PersonEntity person2=new PersonEntity();
person2.setAge(25);
person2.setId(1);
person2.setName("Rose");
personList.add(person2);

return personList;
}
}

 UnicastRemoteObject类 :这个类是远程方法调用的目标,因为它继承自UnicastRemoteObject,这个类的构造器使得它的对象可供远程访问。 

有时候可能不希望服务器类继承UnicastRemoteObject,也许是因为实现类已经继承了其他的类。在这种情况下,需要亲自初始化远程对象,并将它们传给静态的exportObject方法。如果不继承UnicastRemoteObject,可以在远程对象的构造器中像下面这样调用exportObject方法。 

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


4)建立客户端进行测试,注意客户调用的RMI路径必须服务器配置一致

public class Program {
public static void main(String[] args){
try{
//调用远程对象,注意RMI路径与接口必须与服务器配置一致
       PersonService personService=(PersonService) Naming.lookup("rmi://127.0.0.1:6600/PersonService");
List<PersonEntity> personList=personService.GetList();
for(PersonEntity person:personList){
System.out.println("ID:"+person.getId()+" Age:"+person.getAge()+" Name:"+person.getName());
}
}catch(Exception ex){
ex.printStackTrace();
}
}
}

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

服务器程序使用自举注册服务来注册至少一个远程对象。要注册一个远程对象,需要一个RMI URL和一个对实现对象的引用。RMI的URL以rmi:开头,后接服务器以及一个可选的端口号,接着是远程对象的名字。

mi://127.0.0.1:6600/PersonService"

基于安全原因,一个应用只有当它与注册表运行在同一个服务器时,该应用才可以绑定、取消绑定,或重绑定注册对象的引用。


2.学习Spring 封装RMI实现

Spring RMI中,主要有两个类:org.springframework.remoting.rmi.RmiServiceExporter和org.springframework.remoting.rmi.RmiProxyFactoryBean

服务端使用RmiServiceExporter暴露RMI远程方法,客户端用RmiProxyFactoryBean间接调用远程方法。

实现流程:

 (1)在服务端Web工程中添加接口,普通接口即可,无需继承其他

(2)接口的实现类

(3)在服务端中添加Spring配置文件,命名为rmiServer.xml,通过属性注入方式将Bean添加到Spring IoC容器,该Bean的实现类就是org.springframework.remoting.rmi.RmiServiceExporter

(4)客户端调用

在客户端中添加Spring配置文件,命名为rmiClient.xml,通过属性注入方式将接口名与服务端URL这两个属性添加到Spring IoC容器,实现类为org.springframework.remoting.rmi.RmiProxyFactoryBean

(5)接下来调用即可.


二.明日计划

1.做一个Spring RMI的demo,把它部署运行成功;

2.参考师兄日报,学习怎么修改把任务7的成果,实现分布式


三.遇到问题

今天因为一些琐碎的事情,没有及时把Spring MVC的知识点整理出来,明天补上.


四.收获

以上.


禅道进度:http://task.ptteng.com/zentao/task-view-10398.html

计划后天完成提交任务8.


返回列表 返回列表
评论

    分享到