RMI小例子一枚
一个正常工作的RMI系统由下面几个部分组成:
·远程服务的接口定义
·远程服务接口的具体实现
·桩(Stub)和框架(Skeleton)文件 (JDK1.5以后自动生成)
·一个运行远程服务的服务器
·一个RMI命名服务,它允许客户端去发现这个远程服务
·类文件的提供者(一个HTTP或者FTP服务器)
·一个需要这个远程服务的客户端程序
远程服务的接口定义 Server.java:
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Server extends Remote{ //必须继承Remote接口
String hellpWorld(String name) throws RemoteException;
Person getPerson(String name,int age)throws RemoteException;
}
Person对象(网络传输,必须实现序列化):
import java.io.Serializable;
public class Person implements Serializable{
private String name;
private int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
远程服务接口的具体实现 ServerImpl.java:
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
//必须继承UnicastRemoteObject对象
public class ServerImpl extends UnicastRemoteObject implements Server {
protected ServerImpl() throws RemoteException {
super();
}
public String hellpWorld(String name) throws RemoteException {
return name+"你好";
}
public Person getPerson(String name, int age) throws RemoteException {
return new Person(name,age);
}
//没有在接口里定义的方法是本地方法不能被远程调用
public void info(){
System.out.println("我是本地方法");
}
public static void main(String[] args) throws RemoteException, MalformedURLException {
Server imp=new ServerImpl();
//注册远程服务的端口
LocateRegistry.createRegistry(1097);
Naming.rebind("rmi://:1097/jim", imp);
}
}
客户端:
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class RMIClient {
/**
* @param args
* @throws NotBoundException
* @throws RemoteException
* @throws MalformedURLException
*/
public static void main(String[] args) throws MalformedURLException, RemoteException, NotBoundException {
Server ser=(Server) Naming.lookup("rmi://:1097/jim");
System.out.println(ser.hellpWorld("jim"));
System.out.println(ser.getPerson("jim", 24));
}
}
当客户端面向远程服务接口调用远程方法之后,接下来要经过如下几个步骤:
- 本地客户端调用远程服务对象的方法------实际上是调用Stub对象的方法。
- Stub对象其实就是远程服务对象在客户端的代理。Stub对象会对调用请求进行编码,保证远程调用请求可以在网络上传输。所以这一步要求调用远程方法的所以参数都是可序列化的。
- 通过底层网络传输将请求传递到Skeleton。
- Skeleton收到Stub通过网络传输过来的调用请求后,Skeleton对请求进行解码,将请求转换为满足远程服务对象要求的请求
- Skeleton将解码后的请求发送到远程服务对象,让远程服务对象来负责处理调用请求。
- Skeleton收到远程服务对象的执行结果(就是方法返回值)后,再次对执行结果进行编码,因此这一步要求RMI中的方法返回值都是可序列化。
- 通过底层网络传输将处理结果送到Stub
- Stub解码处理结果
- Stub将解码后的符合本地客户端要求的结果送给本地客户端
- 本地客户端收到执行结果。假象就是:本地客户端成功地调用了远程java方法。