天天看点

浅谈RMI - 搭建一个简单的RMI程序声明:本案例使用的IDE是Eclipse,客户端程序和服务器程序位于同一个project中。 一、基本原理二、基本步骤*创建远程接口三、创建远程类四、创建服务器程序五、创建客户端程序六、运行

声明:本案例使用的IDE是Eclipse,客户端程序和服务器程序位于同一个project中。

一、基本原理

RMI是Remote Method Invoke的缩写,是JDK提供的一个完善的、简单易用的远程调用框架,它要求客户端和服务器端都是Java程序。下面简述RMI的基本原理:如下图所示,RMI采用代理来负责客户端和服务器之间socket通信的细节。RMI框架分别为远程对象生成了客户端代理和服务器端代理,位于客户端的代理称为存根(Stub),位于服务器端的代理称为骨架(Skeleton)。

浅谈RMI - 搭建一个简单的RMI程序声明:本案例使用的IDE是Eclipse,客户端程序和服务器程序位于同一个project中。 一、基本原理二、基本步骤*创建远程接口三、创建远程类四、创建服务器程序五、创建客户端程序六、运行

远程对象会在客户端生成存根对象。当客户端调用远程对象的方法时,实际上是调用本地存根的相应方法。然后,存根会把被访问的远程对象名、方法名以及参数编组后发送给服务器,由骨架去调用相应的远程方法并把返回值或异常返回给客户端。

二、基本步骤

一般来说,只要继承java.rmi.server.UnicastRemoteObject类和实现java.rmi.Remote 接口就可以成为远程对象。由于java的单继承,继承了UnicastRemoteObject类之后就不能继承其他的类,这时可以在构造方法中调用exportObect()方法,同样可以将其导为远程对象。实际上,UnicastRemoteObject的构造器也会去调用自身的exportObect()的静态方法。 下面是创建一个RMI程序的基本步骤: (1)创建远程接口,继承java.rmi.Remote接口; (2)创建远程类,实现远程接口; (3)创建服务器程序,在rmiregistry注册表中注册远程对象; (4)创建客户端程序,负责定位远程对象,并且调用远程方法。

*创建远程接口

远程接口中声明了可以被客户端访问的远程方法,远程接口应符合以下条件: (1)直接或间接继承java.rmi.Remote接口; (2)接口中的所有方法声明抛出java.rmi.RemoteException异常或父异常。

package main;

import java.rmi.Remote;
import java.rmi.RemoteException;
// Inherit the java.rmi.Remote interface
public interface HelloService extends Remote {
    // Remote method should throw RemoteException
    public String service(String data) throws RemoteException;
}
           

三、创建远程类

远程类应符合以下条件: (1)继承java.rmi.server.UnicastRemoteObject类并实现远程接口; (2)构造器必须抛出java.rmi.RemoteException异常。

package main;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
// Inherit UnicastRemoteObject and implement HelloService interface
public class HelloServiceImpl extends UnicastRemoteObject
        implements HelloService {

    private static final long serialVersionUID = 1L;
    private String name;

    public HelloServiceImpl(String name) throws RemoteException {
        super();
        this.name = name;
        // UnicastRemoteObject.exportObject(this, 0);
    }

    @Override
    public String service(String data) throws RemoteException {
        return data + name;
    }
}
           

四、创建服务器程序

在这里要介绍几个方法:

  • bind(String name, Object obj): 注册对象,把对象与服务名绑定。如果该服务名已与其他对象绑定,则会抛出NameAlreadyBoundException异常。
  • rebind(String name, Object obj): 注册对象,把对象与服务名绑定。如果该服务名已与其他对象绑定,不会抛异常,而是将新的对象绑定到该服务名上。
  • lookup(String name): 查找对象,返回与指定名称相同的对象。

服务器端首先要创建注册表实例,然后将远程对象注册到注册表上。服务器程序运行就绪之后,不会立即结束,而是去监控客户端的连接。关于服务名的命名格式,推荐使用“rmi://主机名:端口号/实例名”的方式,这样可以避免在远程对象很多的时候因服务名一致而引发的冲突。默认的端口号1099可以省略。

package main;

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 {
            LocateRegistry.createRegistry(1099);

            HelloService service1 = new HelloServiceImpl("service1");
            Context namingContext = new InitialContext();
            namingContext.rebind("rmi://localhost:1099/HelloService1",
                    service1);
        }
        catch (RemoteException | NamingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("Successfully register a remote object.");

    }
}
           

五、创建客户端程序

package main;

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) {
        // TODO Auto-generated method stub
        String url = "rmi://localhost:1099/";
        try {
            Context namingContext = new InitialContext();
            HelloService serv = (HelloService) namingContext.lookup(
                    url + "HelloService1");
            String data = "This is RMI Client.";
            System.out.println(serv.service(data));
        }
        catch (NamingException | RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
           

客户端先根据服务名查找远程对象,然后才能调用远程方法。因此,此处的服务名必须与在服务器中注册的服务名称一致,否则将无法找到远程对象。

六、运行

在Eclipse中先启动Server,然后启动Client即可。