分布式调用rmi

java的一个重要特征就是分布式计算. rmi就是一种非常简单的远程调用协议. 它比web service要简单很多. 但现在java的远程调用越来越趋向使用http, 例如httpclient + xml/json + servlet实现更加开放,简单,mvc,轻量的远程调用. 但REST并不是我们这篇文章要讨论的东西, rmi才是, rmi的应用还是广泛的,例如大名鼎鼎的EJB,就是基于rmi实现的.

rmi的架构分server端和client端, server就是服务提供方,client便是索取服务方. 

  1. Server端需要启动一个RMI的注册表服务先,server端可以想注册表注册要开放的调用引用. 而client端则可以从注册表获取要调用的引用.
    注册表的启动方法为: java bin目录下,运行命令 rmiregistry.
  2. server端向注册表注册.
  3. client端通过jndi获取注册表上的引用. 此引用常被称为stub, 存根.
  4. client调用存根,存根封装了和server端的信息交互, server端的代理封装了信息的解析和对真正引用调用.以上就是 client -- stub ----------- proxy -- server.

rmi调用需要传递值和对象. 其中对象传递分为传递远程对象和传递本地对象.

  1. 传递本地对象, 就是传递一个实现了Serializable的对象, 对象会被序列化传递到client端.
  2. 传递远程对象, 则是传递一个对server端的对象的引用, client端在此引用上的操作都将使用rmi的方式回到server端调用. 有点像 rmi 嵌套 rmi.

至于如何运行一个rmi. 分3步走:

  1. 启动rmiregistry. 
  2. 启动server, 启动server的时候需要给jvm设定codebase参数,告诉rmiregistry去哪下载要注册的interface. 例如: -Djava.rmi.server.codebase=http://localhost:8080/examples/. 想注册表注册服务.
  3. 启动client, 执行调用.

接下来, 是我的一个实现. 实现中涵盖了以上所有的内容. 首先要贴的代码是server端和client端公用的interface与交互类.

package remote;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Compute extends Remote {
	public int sum(int a, int b) throws RemoteException;
	
	public Result mult(int a, int b) throws RemoteException;
	
	public RemoteExec getRemoteExec() throws RemoteException;

}
package remote;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface RemoteExec extends Remote {
	
	public int exec(int a, int b) throws RemoteException;
	public Result execResult(int a, int b) throws RemoteException;

}
package remote;

import java.io.Serializable;

public class Result implements Serializable {
	private static final long serialVersionUID = -4779724309418083812L;
	private int result;
	
	public Result(int r) {
		this.result = r;
	}
	
	@Override 
	public String toString() {
		return ""+result;
	}

}
以上3个类是client和server共有的. 两个实现了remote的interface需要放在一个共享目录,一共注册表能加载到他们.

然后是server端的实现.

package remote;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class Server {

	/**
	 * @param args
	 * @throws RemoteException 
	 * @throws NamingException 
	 */
	public static void main(String[] args) throws RemoteException, NamingException {
		//if (System.getSecurityManager() == null) {
            //System.setSecurityManager(new SecurityManager());
        //}
		
		Compute c = new Compute() {

			@Override
			public int sum(int a, int b) throws RemoteException {
				// TODO Auto-generated method stub
				return a+b;
			}

			@Override
			public Result mult(int a, int b) throws RemoteException {
				// TODO Auto-generated method stub
				return new Result(a*b);
			}

			@Override
			public RemoteExec getRemoteExec() throws RemoteException {
				// TODO Auto-generated method stub
				RemoteExec re =  new RemoteExec() {

					@Override
					public int exec(int a, int b) {
						// TODO Auto-generated method stub
						return a-b;
					}

					@Override
					public Result execResult(int a, int b) {
						// TODO Auto-generated method stub
						return new Result(a*b);
					}
					
					
				};
				RemoteExec stub = (RemoteExec) UnicastRemoteObject.exportObject(re, 0);
				return stub;
			}
			
		};
		
        Compute stub = (Compute) UnicastRemoteObject.exportObject(c, 0);
        //Registry registry = LocateRegistry.getRegistry();
        //registry.rebind(name, stub);
        
        Context namingCtx = new InitialContext();
        namingCtx.rebind("rmi:compute", stub);
        
        
        System.out.println("ComputeEngine bound");
	}

}
最后是client端的实现.

package remote;

import java.rmi.NotBoundException;
import java.rmi.RemoteException;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class Client {

	/**
	 * @param args
	 * @throws RemoteException 
	 * @throws NotBoundException 
	 * @throws NamingException 
	 */
	public static void main(String[] args) throws RemoteException, NotBoundException, NamingException {
            Context ctx = new InitialContext();
            
            String url = "rmi://localhost/compute";
            Compute comp = (Compute) ctx.lookup(url);
            System.out.println(comp.sum(1, 3));
            System.out.println(comp.mult(2, 3));
            
            System.out.println(comp.getRemoteExec().exec(100, 12));
            System.out.println(comp.getRemoteExec().execResult(100, 6));

	}

}
跑一下吧.

转载于:https://my.oschina.net/xpbug/blog/108494

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值