RMI基础

本文讨论的内容:
  • 1、什么是RMI
  • 2、RMI的作用和用途
  • 3、RMI的运行步骤和实现代码
  • 4、RMI优势与劣势的分析

一、什么是RMI 远程方法调用(文档描述)。客户端远程调用服务器端的方法,得到方法的结果(返回值)。这里不花多功夫解释,相信我们在进行代码的分析和运行后会了解什么是RMI。

二、RMI的作用和用途
初学RMI,它能够帮助我们查找并执行远程对象的方法。通俗地说,远程调用就象将一个class放在A机器上,然后在B机器中产生一个代理对象来调用这个class的方法。目前我认为它的作用就是,远程调用方法,实现分布式。

三、RMI的运行步骤和实现代码
1、编写服务器端要被客户端远程调用的对象的接口,这里例如是ServiceInterface。必需继承Remote接口。
Java代码 复制代码 收藏代码
  1. package cn.netjava.ml.jdkrmi;
  2. import java.rmi.Remote;
  3. import java.rmi.RemoteException;
  4. /**
  5. * RMI调用对象接口定义
  6. * @author ml
  7. *
  8. */
  9. public interface ServiceInterface extends Remote{
  10. /**
  11. * 继承于他的远程服务对象所必需实现的方法
  12. * 所有远程服务的方法都必需声明异常
  13. * @param object
  14. * @return
  15. * @throws RemoteException
  16. */
  17. Object service(Object object) throws RemoteException;
  18. }
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、编写要被远程调用对象接口的实现类
Java代码 复制代码 收藏代码
  1. package cn.netjava.ml.jdkrmi;
  2. import java.rmi.RemoteException;
  3. import java.rmi.server.UnicastRemoteObject;
  4. /**
  5. * RMI服务对象接口实现,此对象将被RMI服务器导出做为远程服务对象
  6. *
  7. * @author ml
  8. *
  9. */
  10. public class ServiceImp extends UnicastRemoteObject implements ServiceInterface {
  11. /**
  12. *
  13. */
  14. private static final long serialVersionUID = -2212782652822117319L;
  15. /**
  16. * 父类构造器
  17. *
  18. * @throws RemoteException
  19. */
  20. protected ServiceImp() throws RemoteException {
  21. super();
  22. // TODO Auto-generated constructor stub
  23. }
  24. /**
  25. * 客户端将要调用的方法
  26. */
  27. @Override
  28. public Object service(Object object) throws RemoteException {
  29. // TODO Auto-generated method stub
  30. System.out.println(object);
  31. try {
  32. Thread.sleep(10000);
  33. } catch (InterruptedException e) {
  34. // TODO Auto-generated catch block
  35. e.printStackTrace();
  36. }
  37. return object + " " + System.currentTimeMillis();
  38. }
  39. }
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、编写服务启动类
Java代码 复制代码 收藏代码
  1. package cn.netjava.ml.jdkrmi;
  2. import java.io.IOException;
  3. import java.net.MalformedURLException;
  4. import java.rmi.AlreadyBoundException;
  5. import java.rmi.Naming;
  6. import java.rmi.RemoteException;
  7. import java.rmi.registry.LocateRegistry;
  8. import java.rmi.server.RMISocketFactory;
  9. import java.rmi.server.ServerNotActiveException;
  10. /**
  11. * 启动RMI服务器导出服务对象
  12. *
  13. * @author Administrator
  14. *
  15. */
  16. public class ServiceStart {
  17. public static void main(String[] args) {
  18. int listenPort = 9003;
  19. String serverIP = "localhost";
  20. // 要导出服务对象的名字
  21. String serverObjName = "serverObjName";
  22. // 设置RMI服务监听端口
  23. LocateRegistry.createRegistry(listenPort);
  24. // 设置日志
  25. ServiceImp.setLog(System.out);
  26. // 创建要导出的服务对象,并绑定服务
  27. ServiceImp remoteObj = new ServiceImp();
  28. try {
  29. Naming.rebind("rmi://" + serverIP + ":" + listenPort + "/"
  30. + serverObjName, remoteObj);
  31. System.out.println("RMI服务启动了");
  32. } catch (MalformedURLException e) {
  33. // TODO Auto-generated catch block
  34. e.printStackTrace();
  35. }
  36. } catch (RemoteException e) {
  37. // TODO Auto-generated catch block
  38. e.printStackTrace();
  39. }
  40. }
  41. }
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、编写客户端远程调用类
Java代码 复制代码 收藏代码
  1. package cn.netjava.ml.jdkrmi;
  2. import java.net.MalformedURLException;
  3. import java.rmi.Naming;
  4. import java.rmi.NotBoundException;
  5. import java.rmi.Remote;
  6. import java.rmi.RemoteException;
  7. /**
  8. *
  9. * @author ml
  10. *
  11. *
  12. *报名要和服务器端相同
  13. */
  14. public class RMIClient {
  15. public static void main(String[] args) {
  16. int listenPort = 9003;
  17. String serverIP = "localhost";
  18. String serverObjName = "serverObjName";
  19. try {
  20. ServiceInterface remote = (ServiceInterface) Naming
  21. .lookup("rmi://" + serverIP + ":" + listenPort + "/"
  22. + serverObjName);
  23. for (int i = 0; i < 3; i++) {
  24. //客户端还是要有ServiceInterface对象~~~~
  25. Object object = remote.service("我是远程客户"+i);
  26. System.out.println("客户端调用远程方法了");
  27. System.out.println("远程服务应答"+object);
  28. try {
  29. Thread.sleep(1000);
  30. } catch (InterruptedException e) {
  31. // TODO Auto-generated catch block
  32. e.printStackTrace();
  33. }
  34. }
  35. } catch (MalformedURLException e) {
  36. // TODO Auto-generated catch block
  37. e.printStackTrace();
  38. } catch (RemoteException e) {
  39. // TODO Auto-generated catch block
  40. e.printStackTrace();
  41. } catch (NotBoundException e) {
  42. // TODO Auto-generated catch block
  43. e.printStackTrace();
  44. }
  45. }
  46. }
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)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值