RMI(Remote Method Invocation),远程方法调用。使得客户端的程序可以远程调用服务器中的对象实现远程方法调用的函数接口。接触到这个是在做手写实现一个简单的分布式系统的时候。简单记录一下用RMI实现的第一个例子sayHello。
1.概述
RMI总的来讲有就三个部件,Server端,Client端,还是一个负责完成注册。
过程是这样的,可以被调用的对象先在服务器上进行注册,并和端口绑定。
在本机创建注册表实例并且绑定端口用来接收客户端发送过来的请求。客户端功能实现,远程调用方法。
step1
定义一个远程接口,定义client可以调用的函数,继承remote:
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface HelloRmi extends Remote{
public String sayHello(String name)throws RemoteException;
}
step2
定义一个远程类,实现上面提到的远程调用的函数;
import java.rmi.RemoteException;
public class HelloRmilmpl implements HelloRmi{
public HelloRmilmpl()throws RemoteException{
super();
}
@Override //覆盖原来的sayHello函数
public String sayHello(String name) throws RemoteException {
System.out.println(name+" call rmi!");
return name+"say:hello this is rmi";
}
private static final long serialVersionUID=1L;
}
step3
写服务器端Server的程序:
package com.rmi;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import com.rmi.HelloRmilmpl;
public class RMIServer {
public static void main(String[] args) {
try{
HelloRmi hello=new HelloRmilmpl();//具备远程函数的远程类
HelloRmi stub=(HelloRmi) UnicastRemoteObject.exportObject(hello,9999);//导出远程对象并且在服务器本地保留一个存根stub,方便客户端的调用和访问,这个端口用来接收远程方法调用
LocateRegistry.createRegistry(1099);//注册表接收请求端口为1099
Registry registry=LocateRegistry.getRegistry();//默认注册表端口1099的本地主机的远程对象
registry.bind("hellow",stub);//将对象和一个名字进行绑定,客户端通过这个名字来访问
System.out.println("绑定成功");
}catch (RemoteException e){
e.printStackTrace();
}catch (AlreadyBoundException e){
e.printStackTrace();
}
}
}
step4
client端:
package com.rmi;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class RMIClient {
public static void main(String[] args) {
try{
Registry registry= LocateRegistry.getRegistry("localhost");//返回注册表注册为localhost
HelloRmi hello=(HelloRmi) registry.lookup("hellow");//在注册表中查找名为hellow的远程对象,并且返回这个远程对象在服务器中的存根
String ret = hello.sayHello("111 ");
System. out.println(ret);
}catch(RemoteException e){
e.printStackTrace();
}catch(NotBoundException e){
e.printStackTrace();
}
}
}
step5
开始演示一下,首先开启服务器Server
开启client
调用了远程类的sayHello,实现了输出。
这时候可以再看一下服务器端的状态:
服务器当中记录下了这个sayHello过程的执行经过。
step6(10.23更新)
在原来只有一个远程类和工头请求调用远程函数的基础上,在服务器上面写成了远程类列表,工头处申请两个访问,距离最终目的还是会有不少的距离,但是也还是有一些进展。
记录一下更改的内容:
Server端更改:
ArrayList<HelloRmi> hel=new ArrayList<HelloRmi>();
ArrayList<HelloRmi> stub=new ArrayList<HelloRmi>();
ArrayList<HelloRmi> s;
int mypor=9880;
LocateRegistry.createRegistry(1099);
Registry registry=LocateRegistry.getRegistry();
for (int i=0;i<10;i++){
hel.add(new HelloRmilmpl());
HelloRmi temp=hel.get(i);
stub.add((HelloRmi)UnicastRemoteObject.exportObject(temp,mypor++));
registry.bind("hellow"+i,stub.get(i));
System.out.println("worker"+(i+1)+"绑定成功,port:"+(mypor-1));
}
client端更改:
Registry registry= LocateRegistry.getRegistry("localhost");
HelloRmi hello=(HelloRmi) registry.lookup("hellow1");
String ret = hello.sayHello("Hello111 ");
System. out.println(ret);
HelloRmi hello1=(HelloRmi) registry.lookup("hellow2");
String ret1 = hello.sayHello("Hello222 ");
System. out.println(ret1);
这里直接定义了两个工头来进行调用远程方法。