1,前言
前段时间我从昆明搬家到成都,突然想起还有一个文件落在了昆明,这个文件很重要,该怎么办呢。当然我会不假思索的赶快联系在昆明的朋友,让这个朋友帮我拿到文件,再帮我邮寄过来。本来很棘手而又很重要的一件事,似乎很容易且方便的就解决了。
当我学习java远程方法调用时,突然明白java的这项技术原来借鉴了日常生活中的经常用到而又很简便的方法。我不妨看作是运行在本地的一个jvm,而在昆明的朋友就是一个远程运行的jvm,我通过调用远程jvm的一个方法(拿文件)得到了期望的服务,这个过程就称作远程方法调用,这项技术是Java分布式技术的基础。这项技术对java是很重要的,例如ejb等分布式应用的开发。
2,运行原理
联想开篇的例子。很明显需要两个运行的jvm,为了区别,把这两个jvm分别叫做本地jvm和远程jvm。
对于远程jvm,其是提供服务的一方,因而其先要有一个可供远程调用的方法。考虑到java的面向对象特性,这里使用了一个implements了Remote接口的接口(实现该接口的类,都是一个可以被远程调用的类),然后建立实现了该接口的类(这个类还需要继承UnicastRemoteObject类),这样一个可供远程调用的类就建好了,使用接口是为了向调用这些方法的一方隐藏具体的实现。这只是第一步,我们还要对这个类进行一些处理,以便让其他jvm知道这个类是可以被调用的,以及怎么调用的问题。解决这个问题,就需要把这个类和其url绑定起来。这样远程jvm一方就准备好了。
对于本地jvm。首先得清楚有那些远程方法可供调用,即要知道远程类的url和名字(由于使用了接口,因而是接口的名字)。然后用Naming.lookup方法来构造这个类的实例,那么就可以使用远程的方法了。
这样就完了吗?当然不是,不能忽略了邮局和快递公司。既然是远程,两个jvm之间就要通信,所幸的是Naming.lookup以为我们做好了一切的通信工作,所以这里就不讨论了。
总结起来,java远程调用的运行过程可以分为三步:1)远程服务类(昆明朋友的拿文件方法);2)远程服务类的注册类(得让别人找到嘛);3)本地调用类(调用远程方法)
3,实践
1)远程接口
1. package com.robin.demo.rmi.interf;
2.
3. import java.rmi.Remote;
4. import java.rmi.RemoteException;
5.
6. public interface RmiSample extends Remote {
7. public int sum(int a, int b) throws RemoteException;
8. }
2)远程类
1. package com.robin.demo.rmi.impl;
2.
3. import java.rmi.RemoteException;
4. import java.rmi.server.UnicastRemoteObject;
5.
6. import com.robin.demo.rmi.interf.RmiSample;
7.
8.
9. public class RmiSampleImpl extends UnicastRemoteObject implements RmiSample {
10. /**
11. *
12. */
13. private static final long serialVersionUID = 2742977636753958461L;
14.
15. public RmiSampleImpl() throws RemoteException {
16. super();
17. }
18.
19. public int sum(int a, int b) throws RemoteException {
20. return a + b;
21. }
22.
23. }
3)注册类
1. package com.robin.demo.rmi.server;
2.
3. import java.net.MalformedURLException;
4. import java.rmi.Naming;
5. import java.rmi.RemoteException;
6. import java.rmi.registry.LocateRegistry;
7.
8. import com.robin.demo.rmi.impl.RmiSampleImpl;
9.
10.
11. public class RmiSampleServer {
12.
13. /**
14. * @param args
15. */
16. public static void main(String[] args) {
17. try{
18. LocateRegistry.createRegistry(8808);
19. RmiSampleImpl server= new RmiSampleImpl();
20. Naming.rebind("//localhost:8808/SAMPLE-SERVER" , server);
21. }catch (MalformedURLException me){
22. System.out.println("Malformed URL: " + me.toString());
23. }catch(RemoteException re){
24. System.out.println("Remote Exception: "+re.toString());
25. }
26. }
27.
28. }
4)本地调用远程方法
1. package com.robin.demo.rmi.client;
2.
3. import java.rmi.Naming;
4. import java.rmi.RemoteException;
5.
6. import com.robin.demo.rmi.interf.RmiSample;
7.
8.
9. public class RmiSampleClient {
10.
11. /**
12. * @param args
13. */
14. public static void main(String[] args) {
15. try {
16. String url = "//localhost:8808/SAMPLE-SERVER";
17. RmiSample RmiObject = (RmiSample) Naming.lookup(url);
18. System.out.println(" 1 + 2 = " + RmiObject.sum(1, 2));
19. } catch (RemoteException rex) {
20. System.out.println("Error in lookup: " + rex.toString());
21. } catch (java.net.MalformedURLException me) {
22. System.out.println("Malformed URL: " + me.toString());
23. } catch (java.rmi.NotBoundException ne) {
24. System.out.println("NotBound: " + ne.toString());
25. }
26.
27. }
28.
29. }
4,后记
本文是有感而发写成的。在一些细节方面不是很深入,若想深入研究,可以从两方面着手,一是对java的socket通信机制和java.rmi的源码研究;二是对ejb等分布式开发方面的学习。总之学无止境………
5,参考文章
<1>java远程方法调用(RMI),http://robinjie.iteye.com/blog/34606
<2>java远程方法调用(Remote Method Invocation,RMI),http://www.blogjava.net/yruc/archive/2007/01/11/93215.html