分布式调用rmi
from
http://my.oschina.net/xpbug/blog/108494
java的一个重要特征就是分布式计算. rmi就是一种非常简单的远程调用协议. 它比web service要简单很多. 但现在java的远程调用越来越趋向使用http, 例如httpclient + xml/json + servlet实现更加开放,简单,mvc,轻量的远程调用. 但REST并不是我们这篇文章要讨论的东西, rmi才是, rmi的应用还是广泛的,例如大名鼎鼎的EJB,就是基于rmi实现的.
rmi的架构分server端和client端, server就是服务提供方,client便是索取服务方.
- Server端需要启动一个RMI的注册表服务先,server端可以想注册表注册要开放的调用引用. 而client端则可以从注册表获取要调用的引用.
注册表的启动方法为: java bin目录下,运行命令 rmiregistry.
- server端向注册表注册.
- client端通过jndi获取注册表上的引用. 此引用常被称为stub, 存根.
- client调用存根,存根封装了和server端的信息交互, server端的代理封装了信息的解析和对真正引用调用.以上就是 client -- stub ----------- proxy -- server.
rmi调用需要传递值和对象. 其中对象传递分为传递远程对象和传递本地对象.
- 传递本地对象, 就是传递一个实现了Serializable的对象, 对象会被序列化传递到client端.
- 传递远程对象, 则是传递一个对server端的对象的引用, client端在此引用上的操作都将使用rmi的方式回到server端调用. 有点像 rmi 嵌套 rmi.
至于如何运行一个rmi. 分3步走:
- 启动rmiregistry.
- 启动server, 启动server的时候需要给jvm设定codebase参数,告诉rmiregistry去哪下载要注册的interface. 例如: -Djava.rmi.server.codebase=http://localhost:8080/examples/. 想注册表注册服务.
- 启动client, 执行调用.
接下来, 是我的一个实现. 实现中涵盖了以上所有的内容. 首先要贴的代码是server端和client端公用的interface与交互类.
03 | import java.rmi.Remote; |
04 | import java.rmi.RemoteException; |
06 | public interface Compute extends Remote { |
07 | public int sum( int a, int b) throws RemoteException; |
09 | public Result mult( int a, int b) throws RemoteException; |
11 | public RemoteExec getRemoteExec() throws RemoteException; |
03 | import java.rmi.Remote; |
04 | import java.rmi.RemoteException; |
06 | public interface RemoteExec extends Remote { |
08 | public int exec( int a, int b) throws RemoteException; |
09 | public Result execResult( int a, int b) throws RemoteException; |
03 | import java.io.Serializable; |
05 | public class Result implements Serializable { |
06 | private static final long serialVersionUID = -4779724309418083812L; |
09 | public Result( int r) { |
14 | public String toString() { |
以上3个类是client和server共有的. 两个实现了remote的interface需要放在一个共享目录,一共注册表能加载到他们.
然后是server端的实现.
03 | import java.rmi.RemoteException; |
04 | import java.rmi.server.UnicastRemoteObject; |
06 | import javax.naming.Context; |
07 | import javax.naming.InitialContext; |
08 | import javax.naming.NamingException; |
14 | * @throws RemoteException |
15 | * @throws NamingException |
17 | public static void main(String[] args) throws RemoteException, NamingException { |
22 | Compute c = new Compute() { |
25 | public int sum( int a, int b) throws RemoteException { |
31 | public Result mult( int a, int b) throws RemoteException { |
33 | return new Result(a*b); |
37 | public RemoteExec getRemoteExec() throws RemoteException { |
39 | RemoteExec re = new RemoteExec() { |
42 | public int exec( int a, int b) { |
48 | public Result execResult( int a, int b) { |
50 | return new Result(a*b); |
55 | RemoteExec stub = (RemoteExec) UnicastRemoteObject.exportObject(re, 0 ); |
61 | Compute stub = (Compute) UnicastRemoteObject.exportObject(c, 0 ); |
65 | Context namingCtx = new InitialContext(); |
66 | namingCtx.rebind( "rmi:compute" , stub); |
69 | System.out.println( "ComputeEngine bound" ); |
最后是client端的实现.
03 | import java.rmi.NotBoundException; |
04 | import java.rmi.RemoteException; |
06 | import javax.naming.Context; |
07 | import javax.naming.InitialContext; |
08 | import javax.naming.NamingException; |
14 | * @throws RemoteException |
15 | * @throws NotBoundException |
16 | * @throws NamingException |
18 | public static void main(String[] args) throws RemoteException, NotBoundException, NamingException { |
19 | Context ctx = new InitialContext(); |
21 | String url = "rmi://localhost/compute" ; |
22 | Compute comp = (Compute) ctx.lookup(url); |
23 | System.out.println(comp.sum( 1 , 3 )); |
24 | System.out.println(comp.mult( 2 , 3 )); |
26 | System.out.println(comp.getRemoteExec().exec( 100 , 12 )); |
27 | System.out.println(comp.getRemoteExec().execResult( 100 , 6 )); |
跑一下吧.
No comments:
Post a Comment