如何发布RMI服务;Java实现简易RPC框架

1 、RMI是什么

在 Java 世界里,有一种技术可以实现“跨虚拟机”的调用,它就是 RMI(Remote Method Invocation,远程方法调用)。例如,服务A 在 JVM1 中运行,服务B 在 JVM2 中运行,服务A 与 服务B 可相互进行远程调用,就像调用本地方法一样,这就是 RMI。在分布式系统中,我们使用 RMI 技术可轻松将服务提供者(Service Provider)与服务消费者(Service Consumer)进行分离,充分体现组件之间的弱耦合,系统架构更易于扩展。

2、RMI远程方法调用原理

在这里插入图片描述
方法调用从客户对象经占位程序(Stub)、远程引用层(Remote Reference Layer)和传输层(Transport Layer)向下,传递给主机,然后再次经传 输层,向上穿过远程调用层和骨干网(Skeleton),到达服务器对象。 占位程序扮演着远程服务器对象的代理的角色,使该对象可被客户激活。 远程引用层处理语义、管理单一或多重对象的通信,决定调用是应发往一个服务器还是多个。传输层管理实际的连接,并且追踪可以接受方法调用的远程对象。服务器端的骨干网完成对服务器对象实际的方法调用,并获取返回值。返回值向下经远程引用层、服务器端的传输层传递回客户端,再向上经传输层和远程调用层返回。最后,占位程序获得返回值。
要完成以上步骤需要有以下几个步骤:
(1)、 生成一个远程接口
(2)、 实现远程对象(服务器端程序)
(3)、 生成占位程序和骨干网(服务器端程序)
(4)、 编写服务器程序
(5)、 编写客户程序
(6)、 注册远程对象
(7)、 启动远程对象

3、发布RMI服务

发布的一个RMI服务,我们需做三件事情
1、定义一个RMI接口
2、编写RMI接口的实现类
3、通过JNDI发布RMI服务

3.1 定义一个RMI接口
RMI接口实际上还是一个普通的Java接口,只是RMI接口必须继承java.rmi.Remote,此外,RMI接口内的每个方法必须声明抛出一个java.rmi.RemoteException异常,就像下面这样

package org.bird.rmi2;  
  
import java.rmi.Remote;  
import java.rmi.RemoteException;  
  
public interface CalculateService extends Remote {  
  
    public int add(int a, int b) throws RemoteException;  
}  

继承了Remote接口,实际上就是让JVM知道该接口需要用于远程调用的,抛出RemoteException是为了让调用RMI服务的程序捕获这个异常根据相应异常情况进行后续处理,毕竟远程调用过程中,什么奇怪的事情都有可能发生(如:断网)。需要说明的是,RemoteException是一个”受检异常“,在调用的时候必须使用try…catch…自行处理。

3.2 编写RMI接口的实现类
实现上面的CalculateService比较简单,但是需要注意的是,我们必须让实现类继承java.rmi.server.UnicastRemoteObject类,此外,必须提供一个构造器,并且构造器必须抛出java.rmi.RemoteException异常。所以说,我们使用JVM提供的这一套RMI框架,就必须按照这些要求来实现,否则是无法成功发布RMI服务的。就像下面这样

package org.bird.rmi2;  
  
import java.rmi.RemoteException;  
import java.rmi.server.UnicastRemoteObject;  
  
public class CalculateServiceImpl extends UnicastRemoteObject implements  
        CalculateService {  
    /** 
     *  
     */  
    private static final long serialVersionUID = 1L;  
      
      
    protected CalculateServiceImpl() throws RemoteException {  
        super();  
    }  
  
    public int add(int a, int b) throws RemoteException {  
        return a + b;  
    }  
  
}  

为了满足RMI框架的要求,我们确实需要做很多额外的工作(继承了UnicastRemoteObject类,抛出RemoteException异常)。我们可以通过JVM提供的JNDI(Java Naming and Directory Interface,Java 命名与目录接口)这个API方便的发布RMI服务。

3.3通过JNDI发布RMI服务
发布RMI服务,我们需要告诉JNDI三个基本信息:1.域名或IP地址(host)、2.端口号(port)、3、服务名(service),它们构成了RMI协议的URL

rmi://<host>:<port>/<service> 

如果我们是在本地发布RMI服务,那么host就是localhost。此外RMI默认的端口是1099,我们也可以自行设置port的值(可以与其他端口冲突)。service是基于host与port下唯一的服务名称。需要保证RMI地址的唯一性。对于我们示例,RMI地址为:

rmi://localhost:1099/calculate  

我们提供一个main()方法来发布示例RMI服务,就像下面

package org.bird.rmi2;  
  
import java.net.MalformedURLException;  
import java.rmi.AlreadyBoundException;  
import java.rmi.Naming;  
import java.rmi.RemoteException;  
import java.rmi.registry.LocateRegistry;  
  
public class RMIServer {  
  
    /** 
     * @param args 
     * @throws RemoteException  
     * @throws AlreadyBoundException  
     * @throws MalformedURLException  
     */  
    public static void main(String[] args) throws RemoteException, MalformedURLException, AlreadyBoundException {  
        int port = 1099;  
        LocateRegistry.createRegistry(port);  
        String url = "rmi://localhost:" + port + "/calculate";  
        Naming.bind(url, new CalculateServiceImpl());  
    }  
  
}  

我们通过LocateRegistry.createRegistry()方法在JNDI中创建一个注册表,只需提供一个RMI端口即可。通过Naming.bind()方法绑定RMI地址与服务的实现类。运行这个main()方法,RMI服务就会自动发布,剩下的事情就是写一个RMI客户端来调用刚发布的RMI服务。

4、调用RMI服务

同样,我们也利用一个main()方法来调用RMI服务。调用服务我们只需要知道两个信息:1.RMI请求地址、2.RMI接口(一定不要使用RMI的实现类,否则就是本地调用)。少量代码就能调用刚才发布的RMI服务了,就像下面这样

package org.bird.rmi2;  
  
import java.net.MalformedURLException;  
import java.rmi.Naming;  
import java.rmi.NotBoundException;  
import java.rmi.RemoteException;  
  
public class RMIClient {  
  
    /** 
     * @param args 
     * @throws NotBoundException  
     * @throws RemoteException  
     * @throws MalformedURLException  
     */  
    public static void main(String[] args) throws MalformedURLException, RemoteException, NotBoundException {  
        String url = "rmi://localhost:1099/calculate";  
        CalculateService calculate = (CalculateService) Naming.lookup(url);  
        int sum = calculate.add(100, 400);  
        System.out.println(sum);  
    }  
  
}  

当我们运行以上的main()方法,在控制台看到”500“输出,表明RMI调用成功。
在这里插入图片描述

本文转自:https://www.iteye.com/blog/liangjf85-163-com-2162928
Java实现简易RPC框架参考一:Java实现简易RPC框架(一)
二:Java实现简易RPC框架(二)
三:Java实现简易RPC框架(三)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值