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调用成功。
相关推荐
在Spring框架的支持下,我们可以更方便地将服务发布为RMI服务,使得其他应用程序可以跨JVM(Java Virtual Machine)访问这些服务。下面将详细阐述Spring RMI服务的实现原理、配置过程以及如何自动化发布服务。 首先...
- 在`rmi_spring_server`项目中,包含了服务器端的代码,实现了RMI服务的发布。 - 在`rmi_spring_client`项目中,包含了客户端的代码,实现了对服务器端RMI服务的调用。 通过上述整合,我们可以构建一个健壮的...
3. **配置服务器**:在`applicationContext.xml`文件中配置RMI服务器,包括定义Bean以及暴露RMI服务的相关设置。 4. **web.xml配置**:在Web应用的部署描述符`web.xml`中加载服务器配置,确保RMI服务器在应用启动时...
`RmiServiceExporter`用于发布服务,而`RmiProxyFactoryBean`则用于创建RMI服务的客户端代理。 二、创建Spring RMIServer 2.1 定义远程接口:首先,我们需要定义一个远程接口,比如`MyRemoteService.java`,声明要...
3. 集成文档:可能包含了如何将RMI与Spring框架整合的教程,指导开发者如何在Spring环境中使用RMI-IIOP实现服务的发布和消费。 4. 相关资料:可能包含了关于RMI、IIOP和CORBA的基础知识,以及相关的技术文章和研究,...
2. **RMI服务注册与发现**:插件可以协助开发者在Eclipse内注册RMI服务,并查找和连接远程服务,简化了服务发布和查找的过程。 3. **调试支持**:提供RMI调用的断点调试功能,使得在分布式环境下调试代码变得可能。...
2. **实现远程接口**:创建一个实现了远程接口的类,并且通常会继承`java.rmi.server.UnicastRemoteObject`,以便可以发布到RMI注册表。 3. **导出远程对象**:通过调用`UnicastRemoteObject.exportObject()`方法将...
System.out.println("RMI服务启动"); } catch (Exception e) { e.printStackTrace(); } } } ``` 此部分代码创建了一个RMI服务器,它首先检查是否已经设置了安全管理器,如果没有,则设置一个。接着创建一个...
这得益于JDK5中引入的动态代理技术,该技术允许动态生成Stub和Skeleton类,大大简化了RMI服务的部署过程。 #### JDK5中的RMI新特性 1. **动态代理支持:** 在JDK5之前,开发者需要手动编写大量的代码来生成Stub和...
关于CORBA客户端开发,开发者需要了解如何创建ORB实例、发布和查找服务、以及如何调用远程方法。这个过程通常涉及编写IDL文件来定义服务接口,将其编译为目标语言(如Java),然后在客户端和服务端分别创建ORB并进行...
Spring 提供了简单的方式来发布RMI服务,在服务端,RmiServiceExporter 可以把任何 Spring 管理的bean发布为RMI服务。 (二)Hessian和Burlap Hessian和Burlap是Caucho提供的一种轻量级的RPC框架,它们提供了基于...
- 使用Spring的 `<rmic>` 和 `<rmiServer>` 配置元素可以自动化RMI服务的生成和发布。 3. **创建RMI服务** - 首先,你需要定义一个远程接口,使用`@Remote`注解标记。这个接口声明了所有可被远程调用的方法。 - ...
在实际应用中,开发者通常会先使用CXF来定义并发布Web服务,然后通过RMI注册这些服务。客户端则可以通过RMI接口调用这些服务,而Hessian作为RMI的一种优化实现,可以在底层处理数据的序列化和反序列化,提升服务调用...
接下来,我们来关注Java 5.0中RMI服务的启动方式,这里发生了显著的变化。在Java 5.0之前,通常需要扩展`UnicastRemoteObject`并覆盖`exportObject()`方法。但在Java 5.0中,我们可以直接使用`UnicastRemoteObject....
2. **服务发布**:服务提供者会将服务的相关元数据(如服务类型、版本等)广播到网络,以便服务消费者可以发现。 3. **服务发现**:服务消费者会监听网络中的服务广播,当接收到符合其需求的服务信息时,会获取服务...
RMI(Remote Method Invocation,远程方法调用)是一种Java平台上的技术,允许程序在不同的Java虚拟机(JVM)之间进行分布式通信。在RMI分布式消息传送模型中,这一技术被应用于构建一个商业消息传送平台,该平台由...
Dubbo作为RPC框架,其核心功能就是提供服务的发布、发现和调用机制。 RMI是Java平台上的一个标准RPC实现,它允许Java对象在不同的JVM之间互相调用。RMI的工作原理包括:序列化对象、传输字节流以及反序列化。在...