在说明IPC机制前,首先要了解java自带的RPC机制是怎样实现的。
第一部分:RMI
(1)理论篇
我们想,如果一台机器想要远程调用另一台机器的对象获取数据,我们会立刻想到网络通信了。我们会想到利用TCP/IP套接字通信,但这样并没有用到java面向对象的特点,并且程序开发人员需要了解底层的TCP/IP的知识,为了程序员开发,java实现了通信机制RPC。但RPC在复杂的通信下,支持的也不太好,并且也没有实现面向对象的开发方式。为了解决这些问题,java实现了RMI机制,即远程方法调用机制。
RMI的开发步骤:
第一步:创建远程调用接口和声明远程调用方法,这个接口需要继承Remote,声明的方法需要抛出RemoteException异常,否则会报异常
第二步:创建第一步接口的实现类,这个实现类要继承UnicastRemoteObject,这个实现类中要有这样的构造方法,要抛出RemoteException异常并且继承父类构造方法super(),如
public XxxImpl()throws RemoteException{ super(); } |
第四步:创建客户端
(2)实践篇
第一步:
<pre name="code" class="java">package cn.stq.rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* 定义一个远程调用接口并声明远程调用的方法
* <p>注:这个接口需要继承Remote接口</p>
* @author hadoop
*
*/
public interface IPersonRemote extends Remote {
/**
* 定义一个远程调用方法:说明XX吃XX
* @param name 名称
* @param str 食物
*/
public String eat(String name,String str)throws RemoteException;
/**
* 定义一个远程调用方法:说明XX在睡觉
* @param name
*/
public String sleep(String name)throws RemoteException;
}
第二步:
<pre name="code" class="java">package cn.stq.rmi;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
* 创建远程调用接口的实现类
* @author hadoop
*
*/
public class IPersonRemoteImpl extends UnicastRemoteObject implements IPersonRemote {
private static final long serialVersionUID = 1L;
protected IPersonRemoteImpl() throws RemoteException {
super();
}
@Override
public String eat(String name, String str)throws RemoteException {
return name+"吃"+str;
}
@Override
public String sleep(String name)throws RemoteException {
return name+"在睡觉";
}
}
第三步:
<pre name="code" class="java">package cn.stq.rmi;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
/**
* 服务端
* @author hadoop
*
*/
public class IPersonServer {
public static final String REMOTEURL = "rmi://192.168.1.109:9999/IPersonRemote";
public static void main(String[] args) {
try {
//创建远程调用的对象
IPersonRemote ipr = new IPersonRemoteImpl();
//注册通信端口
LocateRegistry.createRegistry(9999);
//注册通信的路径
Naming.bind(REMOTEURL, ipr);
System.out.println("服务器启动");
} catch (RemoteException e) {
System.out.println("远程调用失败");
e.printStackTrace();
}catch (MalformedURLException e) {
System.out.println("不合法的协议");
e.printStackTrace();
} catch (AlreadyBoundException e) {
System.out.println("对象已经绑定到已具有相关绑定的名称上");
e.printStackTrace();
}
}
}
第四步:
<pre name="code" class="java">package cn.stq.rmi;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
/**
* 远程调用的客户端
* @author hadoop
*
*/
public class IPersonClient {
public static void main(String[] args) {
try {
//调用远程对象,路径必须与服务端已知
IPersonRemote client = (IPersonRemote) Naming.lookup("rmi://192.168.1.109:9999/IPersonRemote");
String eat = client.eat("张三", "香蕉");
String sleep = client.sleep("李四");
System.out.println(eat);
System.out.println(sleep);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (RemoteException e) {
System.out.println("远程调用失败");
e.printStackTrace();
} catch (NotBoundException e) {
System.out.println("未绑定");
e.printStackTrace();
}
}
}
运行结果:
服务端:
客户端:
第二部分:java自带RMI所涉及几个类的详细分析
1、Remote:仅仅是一个标识接口,类似于Serializable,此接口内没有任何的方法,进行创建远程调用的接口时,创建的接口必须继承Remote接口。
在创建远程调用接口时必须注意一下问题:
(1)远程调用接口必须直接或间接继承Remote,且必须声明为public。
(2)在远程接口中声明方法时,除了要抛与应用程序相关的异常外,还必须包括RemoteException(或者它的父异常IOException、Exception)
(3)在远程方法声明时,作为参数或返回值声明的远程对象必须声明为远程接口,而非接口的实现类。