命令行中运行
RMI是一种分布式应用程序开发方法,采用该方法客户端可调用服务器端的远程对象,就像调用客户端自身方法一样。
使用RMI远程调用需要服务器、客户端、客户端辅助设备(Stub)、服务器辅助设备(skeleton)。
在远程方法调用过程中,客户端看起来像是直接调用远程的方法,其实是辅助设备假装成服务对象(但并不是真正的远程服务),由辅助设备去连接服务器,将调用的方法和参数通过socket传递到服务的辅助设备(Skeleton),然后调用真正的服务。
实现一个RMI程序通常要完成以下几个步骤:
(1)创建远程接口定义客户端和远程调用的方法(继承Remote)
(2)创建远程接口实现类并完成服务器端程序编写,这时客户端会调用的对象。
(3)调用rmic命令生成stub和skeleton(现在已经不生成skeleton)
(4)使用rmregistry命令生成RMI注册表(也可在程序中使用LocateRegistry.createRegistry(1099)指定,这样就不需使用命令启动注册表)
(5)运行服务器和客户端程序
下面是一个简单的RMI程序:
MyRemote接口:
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface MyRemote extends Remote {
public String sayHello() throws RemoteException;
}
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {
protected MyRemoteImpl() throws RemoteException {
}
public String sayHello() {
return "Hello";
}
//创建远程对象,使用rebind产生关联,注册名称供客户端查询
public static void main(String[] args) {
try {
MyRemote service = new MyRemoteImpl();
LocateRegistry.createRegistry(1099);
Naming.rebind("rmi://localhost:1099/Hello", service);
System.out.println("Ready...");
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
import java.rmi.Naming;
//为什么在ide编写在dos下编译不通过?
public class MyRemoteClient {
public static void main(String[] args) {
try {
MyRemote service = (MyRemote) Naming.lookup("rmi://localhost:1099/Hello");
String str = service.sayHello();
System.out.println(str);
} catch (Exception e) {
e.printStackTrace();
}
}
}
几点需要注意:
1、远程接口继承Remote接口且所有方法必须声明RemoteException(需通过socket传递)
2、远程服务应该继承UnicastRemoteObject(最简单的创建远程对象的方式)
3、远程服务构造方法声明RemoteException异常,因为父类的构造函数声明了异常
4、可通过rmiregistry或在程序中实现启动RMI注册表(通常采用在程序中的方法,上面的程序使用命令启动出现classnotfound错误,原因不明(rmiregistry命令已在stub.class所在目录启动))