RMI-IIOP与CORBA:实现跨平台通信的有效方案
在当今的软件开发中,跨平台和跨语言的通信需求日益增长。RMI-IIOP和CORBA作为两种重要的技术,为解决这些问题提供了有效的途径。本文将详细介绍RMI-IIOP与CORBA的相关知识,包括它们的特点、如何将RMI对象转换为RMI-IIOP对象、何时使用CORBA,以及一个分布式文件系统通知的示例。
1. RMI-IIOP概述
RMI-IIOP将RMI的一些优点与CORBA的语言独立性相结合。RMI对于开发者来说比CORBA更容易使用,但它的主要局限性在于仅支持Java语言。尽管Java具有平台独立性,但有时需要与用其他语言编写的遗留组件或系统进行交互,而CORBA提供了这样的通信渠道,不过对开发者来说可能是一种痛苦的体验。
RMI-IIOP本质上是Java RMI,但使用IIOP协议进行通信。这意味着普通的RMI对象可以作为CORBA对象暴露给外部系统,同样,外部的CORBA对象也可以通过RMI API进行访问,这都得益于IIOP作为底层通信协议。
然而,IIOP并非专为Java设计。通过IIOP按值传递的对象(实现 java.io.Serializable 而不是 java.rmi.Remote 的对象)会以Java对象的形式在字节流中传递,这意味着通过RMI-IIOP按值传递的任何参数只能由Java客户端读取。幸运的是,CORBA有处理值类型的机制,但这要求客户端实现值类型的相同接口。
此外,CORBA IDL不支持方法重载,结合传递参数时不使用值类型,这在设计使用RMI-IIOP的分布式系统时可能会带来负担。一种设计方法是在为远程对象创建Java接口时,从有限的IDL角度出发思考。虽然仅使用基本类型可能会使代码不够简洁,但互操作性的便利性使其非常值得。
在大多数情况下,RMI-IIOP使CORBA编程变得简单得多,如果不需要CORBA的高级功能,它是Java中与CORBA集成的首选方法。其编程模型与RMI相同,允许Java开发者轻松与其他平台集成。
2. 将RMI对象转换为RMI-IIOP对象
将现有的RMI对象通过RMI-IIOP暴露出来只需要进行少量的工作。以下是具体步骤:
2.1 定义RMI接口
假设我们有一个简单的RMI HelloWorld 接口:
package simple.rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface HelloWorld extends Remote {
public void hello() throws RemoteException;
}
2.2 实现RMI对象
正常的RMI对象实现会扩展 java.rmi.UnicastRemoteObject , HelloWorldImpl 作为普通的RMI对象如下:
package simple.rmi;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class HelloWorldImpl extends UnicastRemoteObject implements HelloWorld {
public HelloWorldImpl() throws RemoteException {
super();
}
public void hello() throws RemoteException {
System.out.println("Hello");
}
}
2.3 修改实现类以支持RMI-IIOP
为了使该对象能够通过RMI-IIOP使用,第一步是让类扩展 javax.rmi.PortableRemoteObject 而不是 java.rmi.UnicastRemoteObject :
package simple.rmi;
import java.rmi.RemoteException;
import javax.rmi.PortableRemoteObject;
public class HelloWorldImpl extends PortableRemoteObject implements HelloWorld {
public HelloWorldImpl() throws RemoteException {
super();
}
public void hello() throws RemoteException {
System.out.println("Hello");
}
}
2.4 生成IDL和IIOP存根
使用JDK中的 rmic 工具生成IDL和IIOP存根。运行 rmic 时,确保 simple.rmi.HelloWorldImpl 在类路径中:
rmic -iiop -idl simple.rmi.HelloWorldImpl
2.5 编写启动RMI-IIOP服务器的主程序
最后一步是编写实际启动RMI-IIOP服务器的主程序。关于与JDK中包含的Java ORB守护进程 orbd 进行通信,包括注册对象和与远程CORBA ORB通信,将在后续的示例中详细介绍。
3. 何时使用CORBA
CORBA是一个开发软件较为困难的平台。它在关键任务软件系统中非常健壮和成功,但学习曲线较陡,开发成本可能较高。CORBA最适合用于必须有多种语言编写的组件或有可能用多种语言编写组件的分布式系统。
如今,Java EE是服务器端应用程序更普遍的标准,它也为其一些组件提供了CORBA支持。如果要创建一个新的Java服务器端应用程序,坚持使用Java EE肯定是最佳选择。如果需要支持用其他语言编写的客户端,可以在以后添加CORBA支持。
以下是在分布式系统中添加CORBA的一些合适场景:
- 当需要与中间件中支持CORBA的遗留系统集成时。
- 当存在用其他语言编写的、Java中没有且对服务器端应用程序至关重要的组件,并且构建CORBA链接比用Java重写组件所需的工作量更小时。
此外,CORBA在与Microsoft .NET平台集成时可能是一种不错的技术。最近有一个开源项目IIOP.NET,它将.NET Remoting(.NET中与RMI等效的技术)与IIOP集成。这个项目使得RMI-IIOP和.NET Remoting之间的集成变得容易,是迈向.NET和Java组件更轻松集成的重要一步。IIOP.NET项目的URL为: http://iiop-net.sourceforge.net/
4. 分布式文件系统通知:一个CORBA系统示例
Java的JDK中没有用于监控文件系统事件的类。文件系统事件包括文件的删除、修改、创建或重命名,这些操作是平台特定的,不仅取决于文件系统类型,还取决于主机操作系统。纯Java实现这种监控的唯一方法是运行一个轮询文件系统并查找更新的程序,这显然不是一种高效的监控机制。
幸运的是,.NET Framework中的 FileSystemWatcher 类可以满足需求。它可以挂钩到Windows操作系统,并通知用户文件系统事件。由于应用程序是用Java编写的,因此需要将这个非Java组件集成到应用程序中,CORBA是一个不错的选择,特别是考虑到IIOP.NET的出现。
4.1 实现步骤
以下是实现该示例的详细步骤:
- 获取远程.NET组件的IDL :
包含RemoteFileSystemWatcher的CORBA对象的IDL如下:
#include "orb.idl"
#include "Predef.idl"
#include "FileNotification.idl"
#ifndef __ConsoleCorbaServer_RemoteFileSystemWatcher__
#define __ConsoleCorbaServer_RemoteFileSystemWatcher__
module ConsoleCorbaServer {
interface RemoteFileSystemWatcher {
void registerNotfication(in ::book::FileNotification notification) raises
(::Ch::Elca::Iiop::GenericUserException);
void removeNotification(in ::book::FileNotification notification) raises
(::Ch::Elca::Iiop::GenericUserException);
void setDirectory(in ::CORBA::WStringValue path) raises
(::Ch::Elca::Iiop::GenericUserException);
};
#pragma ID RemoteFileSystemWatcher
"IDL:ConsoleCorbaServer/RemoteFileSystemWatcher:1.0"
};
#endif
- 生成存根类 :
使用Java IDL编译器idlj生成存根类,将请求代理到运行在.NET平台主机上的CORBA ORB:
idlj RemoteFileSystemWatcher.idl
运行 idlj 后会生成以下文件:
- RemoteFileSystemWatcherStub.java
- RemoteFileSystemWatcher.java
- RemoteFileSystemWatcherHelper.java
- RemoteFileSystemWatcherHolder.java
- RemoteFileSystemWatcherOperations.java
- GenericUserException.java
- GenericUserExceptionHolder.java
- GenericUserExceptionHelper.java
- 定义
FileNotification接口 :
FileNotification接口的IDL如下:
#include "orb.idl"
#ifndef __book_FileNotification__
#define __book_FileNotification__
module book {
interface FileNotification {
void fileModified(
in ::CORBA::WStringValue fileName );
void fileDeleted(
in ::CORBA::WStringValue fileName );
void fileCreated(
in ::CORBA::WStringValue fileName );
};
#pragma ID FileNotification "RMI:book.FileNotification:0000000000000000"
};
#endif
- 生成客户端和服务器存根 :
使用-fall选项运行idlj生成客户端和服务器存根:
idlj -fall FileNotification.idl
生成的文件包括:
- FileNotificationStub.java
- FileNotification.java
- FileNotificationHelper.java
- FileNotificationHolder.java
- FileNotificationOperations.java
- FileNotificationPOA.java
- 实现
FileNotification接口 :
实现FileNotification接口的类如下:
public class FileNotificationImpl extends FileNotificationPOA {
public FileNotificationImpl() {
}
public void fileModified(String fileName) {
System.out.println(fileName + ": Modified");
}
public void fileDeleted(String fileName) {
System.out.println(fileName + ": Deleted");
}
public void fileCreated(String fileName) {
System.out.println(fileName + ": Created");
}
}
- 编写主程序 :
主程序的代码如下:
package book;
import java.util.Hashtable;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import org.omg.CORBA.ORB;
import org.omg.CosNaming.NameComponent;
import org.omg.CosNaming.NamingContext;
import org.omg.CosNaming.NamingContextHelper;
import org.omg.PortableServer.POA;
import org.omg.PortableServer.POAHelper;
import ConsoleCorbaServer.RemoteFileSystemWatcher;
public class FileNotificationImpl extends FileNotificationPOA {
public FileNotificationImpl() {
}
public void fileModified(String fileName) {
System.out.println(fileName + ": Modified");
}
public void fileDeleted(String fileName) {
System.out.println(fileName + ": Deleted");
}
public void fileCreated(String fileName) {
System.out.println(fileName + ": Created");
}
public static void main(String[] args) throws Exception {
Properties props = new Properties();
props.put("org.omg.CORBA.ORBInitialHost", "localhost");
props.put("orb.omg.CORBA.ORBInitialPort", "1049");
ORB orb = ORB.init(args, props);
POA rootPOA = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
rootPOA.the_POAManager().activate();
FileNotificationPOA nPOA = new FileNotificationImpl();
org.omg.CORBA.Object ref = rootPOA.servant_to_reference(nPOA);
FileNotification fileNotification = FileNotificationHelper.narrow(ref);
NamingContext ctx = NamingContextHelper.narrow(orb.resolve_initial_references("NameService"));
NameComponent comp = new NameComponent("FileNotification", " ");
ctx.rebind(new NameComponent[] {comp}, ref);
System.out.println("File Notification bound to local ORB");
Hashtable env = new Hashtable();
env.put("java.naming.factory.initial", "com.sun.jndi.cosnaming.CNCtxFactory");
env.put("java.naming.provider.url", "iiop://localhost:1500");
InitialContext remoteCtx = new InitialContext(env);
java.lang.Object fswRef = remoteCtx.lookup("FileSystemWatcher");
RemoteFileSystemWatcher watcher = (RemoteFileSystemWatcher) PortableRemoteObject.narrow(fswRef, RemoteFileSystemWatcher.class);
watcher.registerNotfication(fileNotification);
System.out.println("File Notification registered on remote server.");
System.out.println("Waiting for file notification events...");
System.out.println();
orb.run();
}
}
5. 运行示例
要运行这个示例,首先需要启动远程CORBA服务器。通过运行 ConsoleCorbaServer.exe (一个编译后的.NET二进制文件)来启动:
ConsoleCorbaServer
ConsoleCorbaServer 会创建一个 RemoteFileSystemWatcher 的C#实例,并通过COS Naming服务将其注册为可通过IIOP使用。默认情况下, ConsoleCorbaServer.exe 中的 RemoteFileSystemWatcher 实例会监控当前工作目录,也可以通过调用其 setDirectory() 方法(通过CORBA暴露)来更改监控目录。
6. 关键CORBA类总结
以下是示例代码中使用的关键CORBA类及其功能总结:
| 类名 | 功能 |
| — | — |
| org.omg.CORBA.Object | 用于表示任何CORBA远程对象引用 |
| org.omg.CORBA.ORB | 用于表示CORBA ORB,提供核心CORBA基础设施服务,并协调CORBA对象方法的调用 |
| org.omg.CosNaming.NamingComponent | 用于表示CORBA名称,名称引用运行在COS Naming服务上的特定对象实例,客户端可以通过名称查找特定对象并获取其引用 |
| org.omg.CosNaming.NamingContext | 用于表示实际的COS Naming服务,用于执行对象查找以获取远程CORBA对象的引用 |
| org.omg.PortableServer.POA | 表示可移植对象适配器,自JDK 1.4起,CORBA规范的POA特性被添加到Java实现中,POA允许CORBA对象轻松部署在不同的CORBA ORB实现上,将CORBA对象引用连接到ORB,以便处理对该引用的传入请求 |
通过以上步骤和示例,我们可以看到RMI-IIOP和CORBA在实现跨平台和跨语言通信方面的强大功能。在实际开发中,根据具体需求合理选择和使用这些技术,可以有效地解决分布式系统中的通信问题。
流程图
graph TD;
A[开始] --> B[将RMI对象转换为RMI-IIOP对象];
B --> C[生成IDL和IIOP存根];
C --> D[编写启动RMI-IIOP服务器的主程序];
D --> E[判断是否需要使用CORBA];
E -- 是 --> F[确定使用CORBA的场景];
F --> G[实现分布式文件系统通知示例];
G --> H[运行示例];
E -- 否 --> I[结束];
H --> I[结束];
总结
本文详细介绍了RMI-IIOP与CORBA的相关知识,包括RMI-IIOP的特点、将RMI对象转换为RMI-IIOP对象的步骤、何时使用CORBA,以及一个分布式文件系统通知的示例。通过这些内容,我们可以看到RMI-IIOP和CORBA在跨平台和跨语言通信方面的重要作用。在实际开发中,开发者可以根据具体需求合理选择和使用这些技术,以实现高效、稳定的分布式系统。
7. RMI-IIOP与CORBA的技术细节分析
7.1 RMI-IIOP的优势与局限
RMI-IIOP结合了RMI的易用性和CORBA的语言独立性,为Java开发者提供了与其他平台集成的便捷方式。其优势主要体现在以下几个方面:
- 编程模型简单 :与RMI的编程模型相同,Java开发者无需学习全新的编程范式,降低了学习成本。
- 跨平台通信 :能够让Java程序与其他语言编写的系统进行交互,打破了语言壁垒。
然而,RMI-IIOP也存在一些局限性:
- 值类型传递问题 :通过IIOP按值传递的对象只能被Java客户端读取,且要求客户端实现值类型的相同接口,增加了开发的复杂度。
- IDL限制 :CORBA IDL不支持方法重载,在设计分布式系统时可能会带来一定的限制。
7.2 CORBA的适用场景分析
CORBA虽然开发难度较大,但在特定场景下具有不可替代的优势。以下是对其适用场景的进一步分析:
- 多语言组件集成 :当分布式系统中需要集成多种语言编写的组件时,CORBA能够提供统一的通信接口,确保不同语言组件之间的无缝协作。
- 关键任务系统 :在对系统的健壮性和可靠性要求极高的关键任务系统中,CORBA的成熟性和稳定性使其成为首选。
8. 分布式文件系统通知示例的深入解读
8.1 示例的架构设计
分布式文件系统通知示例的架构设计旨在实现Java应用程序与.NET组件之间的通信。其主要组成部分包括:
- .NET组件 : FileSystemWatcher 类作为核心组件,负责监控Windows操作系统中的文件系统事件。
- CORBA包装器 :通过CORBA接口将 .NET 组件包装起来,使其能够被Java应用程序访问。
- Java客户端 :实现 FileNotification 接口,接收文件系统事件的通知。
8.2 代码实现的详细解释
以下是对示例代码实现的详细解释:
- 实现 FileNotification 接口 : FileNotificationImpl 类继承自 FileNotificationPOA ,并实现了 FileNotificationOperations 接口中的方法。这些方法用于处理文件系统事件,如文件的修改、删除和创建。
public class FileNotificationImpl extends FileNotificationPOA {
public FileNotificationImpl() {
}
public void fileModified(String fileName) {
System.out.println(fileName + ": Modified");
}
public void fileDeleted(String fileName) {
System.out.println(fileName + ": Deleted");
}
public void fileCreated(String fileName) {
System.out.println(fileName + ": Created");
}
}
- 连接到本地ORB :通过设置
Properties对象,指定ORB的初始主机和端口,然后使用ORB.init()方法初始化ORB。
Properties props = new Properties();
props.put("org.omg.CORBA.ORBInitialHost", "localhost");
props.put("orb.omg.CORBA.ORBInitialPort", "1049");
ORB orb = ORB.init(args, props);
- 创建Portable Object Adapter(POA) :从ORB中获取根POA,并激活它。然后创建一个新的POA,将
FileNotificationImpl实例与该POA关联起来。
POA rootPOA = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
rootPOA.the_POAManager().activate();
FileNotificationPOA nPOA = new FileNotificationImpl();
org.omg.CORBA.Object ref = rootPOA.servant_to_reference(nPOA);
FileNotification fileNotification = FileNotificationHelper.narrow(ref);
- 绑定到COS Naming服务 :通过
NamingContext将FileNotification实例绑定到COS Naming服务,以便其他客户端可以通过名称查找该实例。
NamingContext ctx = NamingContextHelper.narrow(orb.resolve_initial_references("NameService"));
NameComponent comp = new NameComponent("FileNotification", " ");
ctx.rebind(new NameComponent[] {comp}, ref);
- 连接到远程COS Naming服务并查找
RemoteFileSystemWatcher:设置InitialContext的环境属性,连接到远程COS Naming服务,然后查找RemoteFileSystemWatcher实例。
Hashtable env = new Hashtable();
env.put("java.naming.factory.initial", "com.sun.jndi.cosnaming.CNCtxFactory");
env.put("java.naming.provider.url", "iiop://localhost:1500");
InitialContext remoteCtx = new InitialContext(env);
java.lang.Object fswRef = remoteCtx.lookup("FileSystemWatcher");
RemoteFileSystemWatcher watcher = (RemoteFileSystemWatcher) PortableRemoteObject.narrow(fswRef, RemoteFileSystemWatcher.class);
- 注册
FileNotification实例并等待事件 :调用RemoteFileSystemWatcher的registerNotfication()方法,注册FileNotification实例,然后让ORB运行,等待文件系统事件的发生。
watcher.registerNotfication(fileNotification);
System.out.println("File Notification registered on remote server.");
System.out.println("Waiting for file notification events...");
orb.run();
9. 技术对比与选择建议
9.1 RMI-IIOP与其他通信技术的对比
与其他常见的通信技术相比,RMI-IIOP具有独特的优势和劣势。以下是与几种常见技术的对比:
| 技术 | 优势 | 劣势 |
| — | — | — |
| RMI-IIOP | 跨平台通信、编程模型简单 | 值类型传递问题、IDL限制 |
| RESTful API | 轻量级、易于理解和实现 | 对复杂对象的处理能力较弱 |
| gRPC | 高性能、支持多语言 | 需要额外的代码生成和配置 |
9.2 选择建议
在选择通信技术时,需要综合考虑项目的需求、团队的技术栈和系统的架构等因素。以下是一些选择建议:
- 如果项目主要是Java内部的通信 :可以优先考虑使用RMI,其简单易用的特点能够提高开发效率。
- 如果需要与其他语言编写的系统进行交互 :RMI-IIOP或CORBA是不错的选择,尤其是在对系统的健壮性和可靠性要求较高的情况下。
- 如果是构建轻量级的Web服务 :RESTful API可能更适合,其简单的架构和广泛的支持能够快速实现系统的开发。
10. 未来发展趋势
随着技术的不断发展,RMI-IIOP和CORBA也在不断演进。以下是对其未来发展趋势的展望:
- 与新兴技术的融合 :RMI-IIOP和CORBA可能会与微服务、容器化等新兴技术进行融合,以适应不断变化的应用场景。
- 性能优化 :不断优化通信协议和实现方式,提高系统的性能和响应速度。
- 简化开发流程 :通过工具和框架的不断完善,降低开发的复杂度,提高开发效率。
流程图
graph TD;
A[分析项目需求] --> B{选择通信技术};
B -- RMI-IIOP/CORBA --> C[设计分布式系统架构];
B -- RESTful API --> D[设计Web服务接口];
B -- gRPC --> E[生成代码并配置];
C --> F[实现RMI-IIOP/CORBA通信];
D --> G[实现RESTful API通信];
E --> H[实现gRPC通信];
F --> I[测试与优化];
G --> I[测试与优化];
H --> I[测试与优化];
I --> J[部署上线];
总结
本文深入探讨了RMI-IIOP与CORBA的相关技术,包括它们的特点、适用场景、实现步骤和代码示例。通过对分布式文件系统通知示例的详细解读,我们了解了如何使用这些技术实现跨平台和跨语言的通信。同时,通过技术对比和选择建议,为开发者在实际项目中选择合适的通信技术提供了参考。随着技术的不断发展,RMI-IIOP和CORBA有望在未来的分布式系统中发挥更加重要的作用。
超级会员免费看
73

被折叠的 条评论
为什么被折叠?



