本文讨论的内容:
一、什么是RMI 远程方法调用(文档描述)。客户端远程调用服务器端的方法,得到方法的结果(返回值)。这里不花多功夫解释,相信我们在进行代码的分析和运行后会了解什么是RMI。
二、RMI的作用和用途
初学RMI,它能够帮助我们查找并执行远程对象的方法。通俗地说,远程调用就象将一个class放在A机器上,然后在B机器中产生一个代理对象来调用这个class的方法。目前我认为它的作用就是,远程调用方法,实现分布式。
三、RMI的运行步骤和实现代码
1、编写服务器端要被客户端远程调用的对象的接口,这里例如是ServiceInterface。必需继承Remote接口。
Remote 是RMI中一个空的接口
Object service(Object object) throws RemoteException 是我们自定义的一个方法,在将来可以被客户端远程调用,返回客户端想得到的对象,当然可以是空。这里注意必需声明RemoteException 异常。
2、编写要被远程调用对象接口的实现类
除了继承服务对象接口外还要继承UnicastRemoteObject类。这里必须要有的一个是构造器,一个是重写service方法。构造器里面调用super()。查查源码就知道super是指UnicastRemoteObject导出了这个服务对象(serviceImp)。service方法就是将来要被客户端调用的方法,这服务器端执行。
3、编写服务启动类
代码有注释,这里不多做解释了。
4、编写客户端要调用远程对象的接口
这里看起来好像不太明白。简单解释是这样的,客户端要远程调用服务器对象的方法,首先客户端必须要有要被远程调用的对象的接口。这里直接把服务器端的那个ServiceInterface复制过来就行了。有一点必须注意的是。 这个接口名以及接口所在的包名必需和服务器端一样!!这里就不贴代码了。
5、编写客户端远程调用类
6、服务器端编译桩,并把生成的桩复制在客户端的bin目录下
进入windows命令行或linux命令终端。输入rmic。有反应了吧,这就是编译桩的工具和javac类似。如果没有的话可能没有配环境变量。我们先编译生成所有类的class文件,再用cd命令进入工程的bin目录,之后使用rmic cn.netjava.ml.jdkrmi.ServiceImp 命令。
这里一定要加上包名(cn.netjava.ml.jdkrmi)。之后会生成ServiceImp_Stub.class文件,把他复制到客户端的class文件目录里就完成了。
7、分别运行服务器和客户端进行测试
四、RMI优势与劣势的分析
优势:RMI提供了java的远程方法调用,给java的分布式带来了方便。
劣势:个人认为RMI用的还是比较少的。
1、RMI仅仅是JAVA的实现,如果服务器是java,客户端是C++就不行了
2、RMI基于C/S模型 比不上基于B/S模型的其他框架实现如(Hessian和Burlap)。
- 1、什么是RMI
- 2、RMI的作用和用途
- 3、RMI的运行步骤和实现代码
- 4、RMI优势与劣势的分析
一、什么是RMI 远程方法调用(文档描述)。客户端远程调用服务器端的方法,得到方法的结果(返回值)。这里不花多功夫解释,相信我们在进行代码的分析和运行后会了解什么是RMI。
二、RMI的作用和用途
初学RMI,它能够帮助我们查找并执行远程对象的方法。通俗地说,远程调用就象将一个class放在A机器上,然后在B机器中产生一个代理对象来调用这个class的方法。目前我认为它的作用就是,远程调用方法,实现分布式。
三、RMI的运行步骤和实现代码
1、编写服务器端要被客户端远程调用的对象的接口,这里例如是ServiceInterface。必需继承Remote接口。
- package cn.netjava.ml.jdkrmi;
- import java.rmi.Remote;
- import java.rmi.RemoteException;
- /**
- * RMI调用对象接口定义
- * @author ml
- *
- */
- public interface ServiceInterface extends Remote{
- /**
- * 继承于他的远程服务对象所必需实现的方法
- * 所有远程服务的方法都必需声明异常
- * @param object
- * @return
- * @throws RemoteException
- */
- Object service(Object object) throws RemoteException;
- }
package cn.netjava.ml.jdkrmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* RMI调用对象接口定义
* @author ml
*
*/
public interface ServiceInterface extends Remote{
/**
* 继承于他的远程服务对象所必需实现的方法
* 所有远程服务的方法都必需声明异常
* @param object
* @return
* @throws RemoteException
*/
Object service(Object object) throws RemoteException;
}
Remote 是RMI中一个空的接口
Object service(Object object) throws RemoteException 是我们自定义的一个方法,在将来可以被客户端远程调用,返回客户端想得到的对象,当然可以是空。这里注意必需声明RemoteException 异常。
2、编写要被远程调用对象接口的实现类
- package cn.netjava.ml.jdkrmi;
- import java.rmi.RemoteException;
- import java.rmi.server.UnicastRemoteObject;
- /**
- * RMI服务对象接口实现,此对象将被RMI服务器导出做为远程服务对象
- *
- * @author ml
- *
- */
- public class ServiceImp extends UnicastRemoteObject implements ServiceInterface {
- /**
- *
- */
- private static final long serialVersionUID = -2212782652822117319L;
- /**
- * 父类构造器
- *
- * @throws RemoteException
- */
- protected ServiceImp() throws RemoteException {
- super();
- // TODO Auto-generated constructor stub
- }
- /**
- * 客户端将要调用的方法
- */
- @Override
- public Object service(Object object) throws RemoteException {
- // TODO Auto-generated method stub
- System.out.println(object);
- try {
- Thread.sleep(10000);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return object + " " + System.currentTimeMillis();
- }
- }
package cn.netjava.ml.jdkrmi;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
* RMI服务对象接口实现,此对象将被RMI服务器导出做为远程服务对象
*
* @author ml
*
*/
public class ServiceImp extends UnicastRemoteObject implements ServiceInterface {
/**
*
*/
private static final long serialVersionUID = -2212782652822117319L;
/**
* 父类构造器
*
* @throws RemoteException
*/
protected ServiceImp() throws RemoteException {
super();
// TODO Auto-generated constructor stub
}
/**
* 客户端将要调用的方法
*/
@Override
public Object service(Object object) throws RemoteException {
// TODO Auto-generated method stub
System.out.println(object);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return object + " " + System.currentTimeMillis();
}
}
除了继承服务对象接口外还要继承UnicastRemoteObject类。这里必须要有的一个是构造器,一个是重写service方法。构造器里面调用super()。查查源码就知道super是指UnicastRemoteObject导出了这个服务对象(serviceImp)。service方法就是将来要被客户端调用的方法,这服务器端执行。
3、编写服务启动类
- package cn.netjava.ml.jdkrmi;
- import java.io.IOException;
- import java.net.MalformedURLException;
- import java.rmi.AlreadyBoundException;
- import java.rmi.Naming;
- import java.rmi.RemoteException;
- import java.rmi.registry.LocateRegistry;
- import java.rmi.server.RMISocketFactory;
- import java.rmi.server.ServerNotActiveException;
- /**
- * 启动RMI服务器导出服务对象
- *
- * @author Administrator
- *
- */
- public class ServiceStart {
- public static void main(String[] args) {
- int listenPort = 9003;
- String serverIP = "localhost";
- // 要导出服务对象的名字
- String serverObjName = "serverObjName";
- // 设置RMI服务监听端口
- LocateRegistry.createRegistry(listenPort);
- // 设置日志
- ServiceImp.setLog(System.out);
- // 创建要导出的服务对象,并绑定服务
- ServiceImp remoteObj = new ServiceImp();
- try {
- Naming.rebind("rmi://" + serverIP + ":" + listenPort + "/"
- + serverObjName, remoteObj);
- System.out.println("RMI服务启动了");
- } catch (MalformedURLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- } catch (RemoteException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
package cn.netjava.ml.jdkrmi;
import java.io.IOException;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.RMISocketFactory;
import java.rmi.server.ServerNotActiveException;
/**
* 启动RMI服务器导出服务对象
*
* @author Administrator
*
*/
public class ServiceStart {
public static void main(String[] args) {
int listenPort = 9003;
String serverIP = "localhost";
// 要导出服务对象的名字
String serverObjName = "serverObjName";
// 设置RMI服务监听端口
LocateRegistry.createRegistry(listenPort);
// 设置日志
ServiceImp.setLog(System.out);
// 创建要导出的服务对象,并绑定服务
ServiceImp remoteObj = new ServiceImp();
try {
Naming.rebind("rmi://" + serverIP + ":" + listenPort + "/"
+ serverObjName, remoteObj);
System.out.println("RMI服务启动了");
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
代码有注释,这里不多做解释了。
4、编写客户端要调用远程对象的接口
这里看起来好像不太明白。简单解释是这样的,客户端要远程调用服务器对象的方法,首先客户端必须要有要被远程调用的对象的接口。这里直接把服务器端的那个ServiceInterface复制过来就行了。有一点必须注意的是。 这个接口名以及接口所在的包名必需和服务器端一样!!这里就不贴代码了。
5、编写客户端远程调用类
- package cn.netjava.ml.jdkrmi;
- import java.net.MalformedURLException;
- import java.rmi.Naming;
- import java.rmi.NotBoundException;
- import java.rmi.Remote;
- import java.rmi.RemoteException;
- /**
- *
- * @author ml
- *
- *
- *报名要和服务器端相同
- */
- public class RMIClient {
- public static void main(String[] args) {
- int listenPort = 9003;
- String serverIP = "localhost";
- String serverObjName = "serverObjName";
- try {
- ServiceInterface remote = (ServiceInterface) Naming
- .lookup("rmi://" + serverIP + ":" + listenPort + "/"
- + serverObjName);
- for (int i = 0; i < 3; i++) {
- //客户端还是要有ServiceInterface对象~~~~
- Object object = remote.service("我是远程客户"+i);
- System.out.println("客户端调用远程方法了");
- System.out.println("远程服务应答"+object);
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- } catch (MalformedURLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (RemoteException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (NotBoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
package cn.netjava.ml.jdkrmi;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
*
* @author ml
*
*
*报名要和服务器端相同
*/
public class RMIClient {
public static void main(String[] args) {
int listenPort = 9003;
String serverIP = "localhost";
String serverObjName = "serverObjName";
try {
ServiceInterface remote = (ServiceInterface) Naming
.lookup("rmi://" + serverIP + ":" + listenPort + "/"
+ serverObjName);
for (int i = 0; i < 3; i++) {
//客户端还是要有ServiceInterface对象~~~~
Object object = remote.service("我是远程客户"+i);
System.out.println("客户端调用远程方法了");
System.out.println("远程服务应答"+object);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NotBoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
6、服务器端编译桩,并把生成的桩复制在客户端的bin目录下
进入windows命令行或linux命令终端。输入rmic。有反应了吧,这就是编译桩的工具和javac类似。如果没有的话可能没有配环境变量。我们先编译生成所有类的class文件,再用cd命令进入工程的bin目录,之后使用rmic cn.netjava.ml.jdkrmi.ServiceImp 命令。
这里一定要加上包名(cn.netjava.ml.jdkrmi)。之后会生成ServiceImp_Stub.class文件,把他复制到客户端的class文件目录里就完成了。
7、分别运行服务器和客户端进行测试
四、RMI优势与劣势的分析
优势:RMI提供了java的远程方法调用,给java的分布式带来了方便。
劣势:个人认为RMI用的还是比较少的。
1、RMI仅仅是JAVA的实现,如果服务器是java,客户端是C++就不行了
2、RMI基于C/S模型 比不上基于B/S模型的其他框架实现如(Hessian和Burlap)。