图中显示了一个分布式的对象模型。在这个模型中,若是一个对象不只被本地访问,并且还可以被远程访问,就称为远程对象。java
若是一个对象只能被本地访问,就被称为本地对象。web
图中白色的椭圆表示本地对象,深色的椭圆表示远程对象。安全
图中实线表示常规的本地方法调用,虚线表示远程方法调用。服务器
为了保证各个对象之间的可靠地发送消息,该模型的实现一般使用TCP协议做为网络传输层的通讯协议。网络
通常来讲远程对象分布在服务器端,提供各类通用的访问。多线程
对象模型的实现系统的功能:并发
1.把分布在不一样节点上的对象之间发送的消息转换为字节序列,这个过程称为编组。框架
2.经过套接字创建链接而且编组后发送。分布式
3.处理网络链接和传输时候的各类故障。性能
4.为分布在不一样节点上的对象提供分布式垃圾收集机制。
5.为远程方法调用提供安全检查机制。
6.服务端运用多线程或者非阻塞通讯机制,确保远程对象具备良好的并发性能,同时被多个客户访问。
7.建立于特定领域相关的各类本地对象和远程对象。
一些现成的,成熟的分布式对象模型的框架:
1.RMI(Remote Method Invoke,远程方法调用):JDK提供一个完善的,简单易用的远程方法调用框架,它要求客户端和服务端都是java程序。
2.CORBA(Common Object Request Broker Architecture,通用对象请求代理体系结构):分布式对象模型的通用框架,容许不一样的语言编写
的对象可以彼此通讯。
3.SOAP(Simple Object Access Protocol,简单对象访问协议):容许异构的系统之间可以彼此通讯,以xml做为通讯语言。一个系统可以访问另外一个
系统对外公布的web服务。
RMI框架封装了全部底层通讯细节,而且解决了编组,分布式垃圾回收,安全检查和并发性等通用问题。开发人员只须要专一于开发与特定问题领域相关的
各类本地对象和远程对象。
RMI对象为远程对象分布生成了客户端代理和服务端代理。位于客户端的代理类叫作存根(Stub),位于服务端的代理类叫作骨架(Skeleton)。
客户端调用远程对象的一个方法的时候,其实是调用本地的存根对象的对应的方法。
存根对象与远程对象实现了相同的接口。
存根对象采用平台无关的编码方式(java序列化机制)对方法的参数进行编组。
存根对象把如下信息发送给服务器:
1.被访问的远程对象的名字。
2.被调用的方法的名字。
3.编组后的参数的字节序列。
服务器接受到这些信息后,由骨架对象来进行处理:
1.反编组参数。
2.定位要访问的对象。
3.调用远程对象的相应方法。
4.获取方法的结果或者异常信息,进行编组。
5.发送给客户。
建立远程类
远程类就是远程对象所属的类。RMI规范要求远程类必须实现一个接口。此外,为了使得远程类的实例能变成为远程客户提供服务的远程对象,
能够用两种途径中的一种把它导出为远程对象。
1.使远程对象继承java.rmi.server.UnicastRemoteObject类,而且远程类的构造方法必须声明抛出RemoteException。这是最经常使用的方式,
java语言的语言特征是,在构造一个子类的实例时,java虚拟机会先自动调用UnicastRemoteObject父类的不带参数的构造方法,它的定义如
下:
protected UnicastRemoteObject() throws RemoteException
{
this(0);
}
protected UnicastRemoteObject(int port)throws RemoteException
{
this.port = port;
exportObject((Remote)this,port);
}
由此,UnicastRemoteObject类的构造方法会调用自身的静态方法exportObject(Remote obj,int port)。该方法负责把参数obj指定的对象导出为
远程对象,使得它具备相应的存根,而且使得它可以监听远程客户的请求。参数port指定监听的端口,若是取值为0,表示任意一个匿名端口。
2.若是一个远程对象已经继承了一个类,没法再继承UnicastRemoteObject类,那么能够再构造方法中调用UnicastRemoteObject类的静态
exportObject()方法。一样,远程类的构造方法必须声明抛出RemoteException异常。
远程类的注意事项:
1.远程类的构造方法必须声明抛出RemoteException,若是导出失败,就会抛出这种异常。
2.全部远程方法必须抛出RemoteException。
3.在远程类中能够定义一些本地方法,即没有在远程接口中声明的方法。这些方法无需抛出RemoteException.它们只能被本地调用,不容许被
远程调用。
4.UnicastRemoteObject类覆盖了Object类的hashCode(),equals()和clone()方法。若是一个远程对象继承了UnicastRemoteObject类,就能够
继承它的这些方法。
查找远程对象
1.jdk1.3及之前版本,jdk的bin目录下有一个rmiregistry.exe程序。服务器向rmiregistry注册表注册远程对象。
2.jdk1.3之后,rmi的命名服务API被整合到JNDI(java Naming and Directory Interface,java名字与目录服务)中。
在JNDI中,javax.naming.Context接口声明了注册,查找以及销毁对象的方法。
public void bind(String name,Object obj)
注册对象,把对象与一个名称绑定。若是该名字已经与其余对象绑定,就会抛出NameAlreayBoundException。
public void rebind(String name,Object obj)
若是绑定了,就覆盖绑定。
lookup(String name)
查找对象
unbind(String name)
注销对象
段1:
HelloService helloService = new HelloServiceImpl("service1");
Context namingContext = new InitialContext();
namingContext.rebind("rmi:HelloService1",helloService);
段分析:
默认状况下,InitialContext的rebind()方法会把HelloServiceImpl对象注册到本地主机上的监听1099端口的rmiregistry注册表中,
而且赋予特定的名字HelloService1,该HelloServiceImpl的完整名字为:
rmi://localhost:1099/HelloService1
能够把段1改写为:
段2:
namingContext.rebind("rmi://localhost:1099/HelloService1",helloService);
或者
段3:
namingContext.rebind("rmi://localhost/HelloService1",helloService);
客户端获取远程对象
段4:
Context namingContext = new InitialContext();
HelloService service1 == (HelloService)namingContext.lookup("rmi://localhost/HelloService1");
客户端必须提供完整名字:
rmi://服务端的名字:端口号/对象的注册名字