远程方法调用
1.概述
分布式计算的关键是远程方法调用,在一台计算机上的某些代码希望调用另一台计算机上的某个对象的方法。本文介绍的RMI协议就可以解决这种问题。
2.工作原理
基本结构如上:
1.当客户端要调用远程方法时,实际上调用的是保存在客户端的一个普通对象,叫存根(stub)
存根将远程方法所需参数打包成一组字节。对参数编码的过程称为参数编组,目的是转换成适合在虚拟机之间进行传递的格式。最后存根将此信息发送给服务器。
2.服务端收到客户端发来的消息,定位要调用的远程对象,调用所需方法,传递参数;捕获返回值或者调用产生的异常;将返回值编组,打包送给客户端存根。
3.示例Demo
/**
* @Auther: 18030501
* @Date: 2018/11/1 20:27
* @Description:
*/
public interface IHello extends Remote, Serializable {
public String sayHelloToSomeBody(String name) throws RemoteException;
}
/**
* @Auther: 18030501
* @Date: 2018/11/1 20:28
* @Description: 继承UnicastRemoteObject表示HelloImpl是一个单独的、不能复制的、远程的对象
*/
public class HelloImpl extends UnicastRemoteObject implements IHello {
// 构造方法需要抛出RemoteException异常
public HelloImpl() throws RemoteException {
}
@Override
public String sayHelloToSomeBody(String name) throws RemoteException {
System.out.println("你好:" + name);
return "OK";
}
}
/**
* @Auther: 18030501
* @Date: 2018/11/1 20:30
* @Description:
*/
public class HelloServer {
/**
* 注册服务共有三种方式:
* LocateRegistry 类的对象的 rebind() 和 lookup() 来实现绑定注册和查找远程对象的
* 利用命名服务 java.rmi.Naming 类的 rebind() 和 lookup() 来实现绑定注册和查找远程对象的
* 利用JNDI(Java Naming and Directory Interface,Java命名和目录接口) java.naming.InitialContext 类来 rebind() 和 lookup() 来实现绑定注册和查找远程对象的
*/
public static void main(String[] args) {
try {
// 创建一个远程对象
IHello hello = new HelloImpl();
// 使用自举注册服务注册对象到注册表中
LocateRegistry.createRegistry(8888);
// rmi://host:port/远程对象名,远程对象名是要与此对象绑定的
Naming.bind("rmi://10.49.2.18:8888/RHello", hello);
System.out.println("等待客户端调用...");
} catch (RemoteException e) {
e.printStackTrace();
} catch (AlreadyBoundException e) {
System.out.println("已经绑定");
e.printStackTrace();
} catch (MalformedURLException e) {
System.out.println("无效url");
e.printStackTrace();
}
}
}
/**
* @Auther: 18030501
* @Date: 2018/11/1 20:30
* @Description:
*/
public class HelloClient {
public static void main(String[] args) throws Exception {
// 指定服务器与远程对象名字
String url = "rmi://10.49.2.18:8888/RHello";
String[] list = Naming.list(url);
for (String s : list) {
System.out.println(s);
}
IHello hello = (IHello) Naming.lookup(url);
hello.sayHelloToSomeBody("拿着核武器的程序员");
}
}