rmi入门
来源:互联网 发布:淘宝网安全套 编辑:程序博客网 时间:2024/06/06 01:02
先来一个最简单的例子:
1.业务接口类
package Simple;import java.rmi.Remote;import java.rmi.RemoteException;public interface Business extends Remote{String doBusiness(String businessCode) throws RemoteException;}
2.业务实现类
package Simple;import java.rmi.RemoteException;import java.rmi.server.UnicastRemoteObject;public class BusinessImpl extends UnicastRemoteObject implements Business{protected BusinessImpl() throws RemoteException {super();// TODO Auto-generated constructor stub}/** * */private static final long serialVersionUID = 1L;@Overridepublic String doBusiness(String businessCode) throws RemoteException {// TODO Auto-generated method stubreturn businessCode + " has been done!";}}
3.Server类
package Simple;import java.rmi.Naming;import java.rmi.registry.LocateRegistry;public class SimpleServer {public static void main(String[] args)throws Exception{Business busi = new BusinessImpl();LocateRegistry.createRegistry(1097);Naming.rebind("rmi://localhost:1097/busi",busi);}}
4.Client类
package Simple;import java.rmi.Naming;public class Client {public static void main(String[] args)throws Exception{Business busi = (Business)Naming.lookup("rmi://localhost:1097/busi");System.out.println(busi.doBusiness("001"));}}
备注说明:
1.从JDK5.0开始,rmi编程不再需要编程人员借助rmic生成stub等辅助类,也不需要手动启动Register。也就是说这些工作JDK已经帮你做好啦
2.EJB的SessionBean其实就是rmi技术和JNDI技术的结合,上述的例子是把业务对象(或stub)存储在Register中,而EJB则把业务对象(或stub)存储在JDNI空间里.
3.LocateRegistry.createRegistry(1097);这里的1097(默认为1099)我们称之为通讯端口或者查找端口,服务端在createRegistry时实际上会new ServerSocket(1097),客户端的socket)通过与端口号为1097的服务端端口互联lookup到busi对象(实际上是stub,为方便描述,下文不再特别指出)。客户端获取到的busi(stub)对象在和服务端的sketon对象进行通讯时实际上也会建立socket连接,数据传输时的ServerSocket也需要一个端口(不同于通讯端口),我们称为之数据端口。这个ServerSocket是在BusinessImpl的父类UnicastRemoteObject的构造方法中初始化的,默认调用new ServerSocket(0),即随便选择一个端口通讯。但在生产环境中,防火墙往往限制通讯端口,只允许部分端口开放。所以上述程序可能会无法穿透防火墙,这时候我们可以强行绑定数据端口.
package Simple;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import java.rmi.Naming;import java.rmi.registry.LocateRegistry;import java.rmi.server.RMISocketFactory;public class Server{public static void main(String... args) throws Exception{RMISocketFactory.setSocketFactory(new RMISocketFactory(){@Overridepublic ServerSocket createServerSocket(int port) throws IOException {if(port == 0)port = 14800;return new ServerSocket(port);}@Overridepublic Socket createSocket(String host, int port)throws IOException {return new Socket(host,port);}});LocateRegistry.createRegistry(1097);Business busi = new BusinessImpl();Naming.rebind("rmi://localhost:1097/busi",busi);}}
我们通过RMISocketFactory.setSocketFactory来控制绑定生成ServerSocket的端口号.在这里LocateRegistry.createRegistry时会调用匿名内部类的createServerSocket生成new ServerSocket(1097),在new BusinessImpl()时会调用匿名内部类的createServerSocket生成new ServerSocket(14800)(原来port=0进行了重绑定),同时也会调用匿名内部类的createSocket生成new Socket("localhost",1097)。在这里一定要注意new BusinessImpl()在setSocketFactory之后才会绑定成功。
我们也可以把LocateRegistry.createRegistry是生成ServerSocket的策略和new BusinessImpl()生成ServerSocket和Socket的策略区别开来,如下:
package Simple;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import java.rmi.Naming;import java.rmi.registry.LocateRegistry;import java.rmi.server.RMIClientSocketFactory;import java.rmi.server.RMIServerSocketFactory;import java.rmi.server.RMISocketFactory;public class Server{public static void main(String... args) throws Exception{RMISocketFactory.setSocketFactory(new RMISocketFactory(){@Overridepublic ServerSocket createServerSocket(int port) throws IOException {if(port == 0)--没有作用了(肯定==0)port = 14800;return new ServerSocket(port);}@Overridepublic Socket createSocket(String host, int port)throws IOException {return new Socket(host,port);}});LocateRegistry.createRegistry(1097,new RMIClientSocketFactory(){@Overridepublic Socket createSocket(String host, int port)throws IOException {return new Socket(host,port);}},new RMIServerSocketFactory(){@Overridepublic ServerSocket createServerSocket(int port) throws IOException {return new ServerSocket(port);}});Business busi = new BusinessImpl();Naming.rebind("rmi://localhost:1097/busi",busi);}}
显然LocateRegistry.createRegistry会使用参数RMIClientSocketFactory的createServerSocket去new ServerSocket(1097).
而new BusinessImpl()还会使用RMISocketFactory.setSocketFactory参数中相关方式,new ServerSocket(34800)和new Socket("localhost",1907).这时候方法中if(port==0)的判断也没有意义了(肯定==0了,LocateRegistry.createRegistry也不会使用这里的工厂生成serverSocket(1907)了)。
再来一种更简单的实现(需要对BusinessImpl进行一点改进)
package Simple;import java.rmi.RemoteException;import java.rmi.server.UnicastRemoteObject;public class BusinessImpl extends UnicastRemoteObject implements Business{protected BusinessImpl() throws RemoteException {super();}protected BusinessImpl(int port) throws RemoteException{super(port);}/** * */private static final long serialVersionUID = 1L;@Overridepublic String doBusiness(String businessCode) throws RemoteException {// TODO Auto-generated method stubreturn businessCode + " has been done!";}}
package Simple;import java.rmi.Naming;import java.rmi.registry.LocateRegistry;public class Server{public static void main(String... args) throws Exception{LocateRegistry.createRegistry(1097);Business busi = new BusinessImpl(34880);Naming.rebind("rmi://localhost:1097/busi",busi);}}
够简单的吧,哈哈。
最后再来谈谈默认的套接字工厂吧。
默认的套接字工厂实现通过三层方法来创建客户机套接字。首先,尝试进行到远程 VM 的直接套接字连接。如果该操作失败(因防火墙的问题),则运行时使用具有服务器显式端口号的 HTTP。如果防火墙不允许此类型的通信,则服务器上的 cgi-bin 脚本的 HTTP 用于 POST(发送)该 RMI 调用。
sun.rmi.transport.proxy.RMIMasterSocketFactory失败后,会使用另外两个类sun.rmi.transport.proxy.RMIHttpToPortSocketFactory和sun.rmi.transport.proxy.RMIHttpToCGISocketFactory来实现通过HTTP协议,不过这个需要服务器端配合。在jdk文档下有一个例子docs\technotes\guides\rmi\archives里面有Servlet实现。
参与文献:
(1)http://www.huomo.cn/developer/article-1b147.html 让JAVA的RMI彻底穿透防火墙
(2)http://hi.baidu.com/netjava/item/c2efd413ce50d2fa9c778a1c RMI穿透防火墙
(3)http://skanion.iteye.com/blog/1168747 RMI心得(注册端口)
(4)http://blog.csdn.net/ktyl2000/article/details/4485896 RMI远程调用时的内外网端口映射问题(RMI远程调用如何穿透防火墙)
(5)http://www.blogjava.net/china-qd/archive/2006/04/25/42927.html 用RMI进行远程方法调用
(6)http://blog.csdn.net/sun_boyhappy/article/details/5655014 RMI IP绑定和端口固定
(7)http://bbs.csdn.net/topics/220029980 RMISocketFactory的含义和RMI的理解
(8)java_RMI技术讲解.doc
(9)RMI开发权威指南.pdf
- RMI 入门
- RMI入门
- rmi入门
- RMI入门
- rmi入门
- RMI 入门
- RMI入门
- Java2 RMI 入门
- Java RMI-IIOP 入门
- Java RMI入门
- Java RMI-IIOP 入门
- RMI 用法入门
- RMI实例入门
- RMI实例入门
- RMI实例入门
- Java RMI 入门
- Java RMI 入门
- Java RMI-IIOP 入门
- VS2008 ”无法执行添加/移除操作,因为代码元素是只读的“解决方法
- 设计模式之工厂方法
- svnant
- 玩玩Windows Azure
- 移植java web 项目到go语言要解决的一系列问题
- rmi入门
- Bloom Filter
- HDU 2007
- VC下显示位图的几种方法
- Linux下yum命令概要与用法
- strstr fuction
- UVA 11783 Nail【简单线段相交判断 附YY加强版】
- MFC中怎样将位图写入指定的Picture控件中,两种方式:1 加载已有位图 2读取位图文件;另外CreateDIBitmap的用法和StretchDIBits用法举例
- maven3 自学笔记(一) Maven依赖