发表于: 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.
评论