65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 IIOP.NET 构建 .NET 和 J2EE 分布式对象系统

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (47投票s)

2003 年 7 月 1 日

7分钟阅读

viewsIcon

312819

downloadIcon

3640

本文演示了 IIOP.NET 的使用

引言

在微软的设想中,下一代分布式系统将通过 WebServices 进行通信。WebServices 在集成异构的松耦合系统方面非常出色,但它们也有局限性:不支持远程对象引用。实际上,它们是无状态的,更接近远程方法调用而非分布式对象系统。此外,SOAP 和 XML 绝非压缩格式,倾向于非常冗长。

.NET 和 J2EE 是两个相似但又不相关的世界:目前它们只能通过 WebServices 进行交互。这两个平台都提供了构建紧耦合分布式对象系统的绝佳机制:.NET 的 Remoting 和 Java 的 RMI,但遗憾的是,它们依赖于不兼容的标准。幸运的是,.NET 的 Remoting 是高度可配置的:可以通过一个不同的序列化和反序列化对象格式化程序以及一个不同的传输通道来实现。

图 1:.NET 通道概述

本文将展示 .NET 和 J2EE 平台如何紧密地协同工作,这在开发分布式企业应用程序时常常需要。为此,我们使用了一个开源的自定义 Remoting 通道,称为 IIOP.NET。

关于 IIOP.NET

IIOP.NET 是一个基于 IIOP 协议的 .NET Remoting 通道。IIOP 是 CORBA 标准定义的协议,与 Java 的 RMI/IIOP 使用的协议相同。IIOP.NET 充当 ORB(CORBA 对象请求代理),它将 .NET 的类型系统转换为 CORBA 的类型系统并反之,从而使您应用程序中定义的那些对象可以被其他 ORB 访问。RMI/IIOP 由于 Java 类型系统的某些限制,只实现了 ORB 功能的一个子集,并为 J2EE 平台提供了与 IIOP.NET 相同的功能。

图 2:分布式对象系统概述

使用 IIOP.NET 几乎和使用内置的 Remoting 一样简单。以下示例将向您展示如何使用 IIOP.NET 从 Java 访问 .NET 服务。

IIOP.NET 是一个托管在 sourceforge 上的开源项目(http://iiop-net.sourceforge.net/)。它由 Dominic Ullmann 作为他在 ETH-Z 的文凭论文的一部分开发;目前由他目前的雇主 (http://www.elca.ch) 赞助进一步工作。

毫不奇怪,IIOP.NET 并不是您为此目的可以使用的唯一软件。首先,开源项目 Remoting.Corba 在目标上非常相似,但没有用于从 dll 生成 IDL 的生成器,并且目前不支持 CORBA 的 valuetypes;其次,Borland 的 Janeva 承诺做同样的事情,但既不免费也不可用(应于 2003 年夏季发布)。我们选择 IIOP.NET 是因为它免费、可用,并且有一个工具可以自动生成 IDL。

示例:访问通用集合服务

您遇到的问题:您刚刚使用 .NET 实现了一个很棒的服务,但您的客户坚持使用 Java 客户端;您不能使用 WebServices,因为客户端软件需要保留对服务器上单个对象的引用:这在使用 WebServices 时是无法实现的,除非您实现自己的命名服务、租约管理器和分布式垃圾回收。更合适的方法是在 Java 端使用 RMI/IIOP,在 .NET 端使用 IIOP.NET。

本文围绕一个非平凡的示例(IIOP.NET 发布中的 GenericCollection 教程:一个 .NET 服务器提供对由键/值对组成的集合的访问。客户端可以获取一个集合,通过添加更多对来修改它,或查询其中包含的对。这要求客户端持有服务器上对象的引用。

为了简单起见,我们将专注于对象分发,而忽略所有与并发相关的问题。

步骤 1:安装 IIOP.NET

您会找到几个目录

  • IIOPChannel 包含通道代码
  • CLSToIDLGenerator 包含一个生成器,用于从 .NET 程序集创建 IDL 定义文件
  • Examples 包含示例和教程代码。本文介绍的是 GenericCollections

要使用 IIOP.NET,您需要 Microsoft 的 .NET Framework(1.0 或 1.1)和 C# 编译器。演示的 Java 部分需要任何支持 RMI/IIOP 的 Java 系统(例如 Sun 的 Java SDK 1.4)。

要安装 IIOP.NET,首先解压;然后将您的 Java SDK lib 目录中的 ir.idlorb.idl 文件复制到 IIOP.NET 的 IDL 目录。在主目录中执行 nmake 进行编译。

步骤 2:定义服务

定义 .NET 服务时,您可以选择按引用封送的对象(继承自 MarshalByRefObject)和按值封送的对象(实现 ISerializable 或带有 SerializableAttribute 属性)。在 GenericCollections 示例中,对象(不含实现)定义如下:

namespace Ch.Elca.Iiop.Demo.StorageSystem {
         [Serializable]
         public struct Entry {
                 public string key;
                 public string value;
         }
         public class Container: MarshalByRefObject {
                 public Container() {...}
                 public Entry[] Enumerate() {...}
                 public void    SetValue(string key, string value) {...}
                 public void    SetEntry(Entry e) {...}
                 public String  GetValue(string key) {...}
         }
         public class Manager: MarshalByRefObject {
                 public Manager() {...}
                 public Container   CreateContainer() {...}
                 public Container[] FilterContainers(Entry[] filter) {...}
                 public void        DeleteContainer(Container c) {...}
         }
}

实际上,Manager 和 Container 对象保留在服务器上。客户端仅接收它们的远程引用,并使用代理对象,该对象对方法调用进行序列化(即编码)并将其转发到服务器。另一方面,Entry 结构被完全复制到客户端,客户端使用其自己的 Entry 克隆。

您现在可以将托管对象提供给(IIOP)世界的其余部分

public class Server {
    [STAThread]
    public static void Main(string[] args) {
        // register the channel
        int port = 8087;
        IiopChannel chan = new IiopChannel(port);
        ChannelServices.RegisterChannel(chan);
        // publish the adder
        Manager manager = new Manager();
        string objectURI = "manager";
        RemotingServices.Marshal(manager, objectURI);
         
        Console.WriteLine("server running");
        Console.ReadLine();
    }
}

上述代码安装了一个监听 URI iiop://:8087/ 的 ORB,并将一个管理器实例以“manager”的名称注册到所有通道。管理器对象将处理所有请求(实际上,这是一个服务器激活的单例对象)。

步骤 3:创建 IDL 描述

为了能够从 Java 访问这些对象,必须提供它们的定义。由于 Java 不理解 .NET 的元数据,我们使用 IIOP.NET 的 CLSToIDLGenerator 工具以 IDL 格式创建对象的描述;该工具以一个类型和一个程序集作为输入,并输出相应的 IDL 定义文件。它还会递归地输出所有其他使用的类型的定义。

调用

CLSToIDLGenerator Ch.Elca.Iiop.Demo.StorageSystem.Manager Service.dll

为 Service.dll 程序集中定义的 Manager 类型(需要完整的类型名称)及其所有其他使用的类型生成描述。会创建 Manager.idl、Container.idl 和 Entry.idl。

步骤 4:从 IDL 创建 Java 存根

Java SDK 提供了 idlj 编译器来为 IDL 文件生成 Java 存根。请注意,您还需要另外两个 IDL 文件存在于您的 Java SDK 中:orb.idlir.idl,它们包含您 Java 平台的所有预定义 CORBA 对象。

步骤 5:实现客户端

现在您可以实现一个客户端,该客户端访问先前定义的远程对象。

import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import Ch.Elca.Iiop.GenericUserException;
import Ch.Elca.Iiop.Demo.StorageSystem.*;

Manager m = null;
try {
         InitialContext ic = new InitialContext();
         Object obj = ic.lookup("manager");
         m = (Manager) PortableRemoteObject.narrow(obj, Manager.class);
         ... use m ...
} catch (Exception e) {
         System.out.println("Exception: " + e.getMessage());
}

这段代码获取了远程对象的引用。现在您可以像调用普通方法一样调用远程对象中定义的方法

Container c = m.CreateContainer();
c.SetValue("name","Patrik");

仍然有一个棘手之处:您必须编写并实现 EntryImpl 类。ManagerContainer 类型是通过引用访问的,即 idlj 生成一个代理,该代理将所有方法调用转发到服务器。而 Entry 结构被复制到客户端(这对应于 .NET 中标记为可序列化的类,以及 CORBA 中的 valuetypes):因此,您需要为所有方法提供本地实现(idlj 只提供一个抽象类)。

package Ch.Elca.Iiop.Demo.StorageSystem;
public class EntryImpl extends Entry { }

由于 Entry 没有需要实现的方法(只有字段),因此它的实现很简单,是一个空的类定义。

步骤 6:运行客户端和服务器

最后一步,运行分布式应用程序。首先,启动服务器

D:\Demo\net:> Server
server running

然后是客户端

java -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory 
         -Djava.naming.provider.url=iiop://:8087 Client

URL 的互联网地址部分被传递给 JVM,以告知 RMI/IIOP 在哪里可以找到命名服务。

Java 客户端会提示您执行一个操作。首先输入“1”创建一个新集合,然后插入一些键值对,最后以空键终止。请记住,您发出的每个命令都在服务器上执行;事实上,通过启动两个客户端,您将访问完全相同的数据。

以下是一个小会话日志

Main Menu:
0. Terminate
1. Create Container
2. Select Container
1

Container Menu:
0. Return to previous menu
1. Set Entry
2. Show Entries
1
Enter an key / value pair:
  key: site
value: CodeProject

Container Menu:
0. Return to previous menu
1. Set Entry
2. Show Entries
1
Enter an key / value pair:
  key: URL
value: http://codeproject.org.cn

Container Menu:
0. Return to previous menu
1. Set Entry
2. Show Entries
2
List Entries
  Entry[site] = CodeProject
  Entry[URL] = http://codeproject.org.cn

Container Menu:
0. Return to previous menu
1. Set Entry
2. Show Entries
0

Main Menu:
0. Terminate
1. Create Container
2. Select Container
2

Select Containers: enter a list of key / values pairs; terminate with an empty key
  key: site
value: CodeProject
  key:

Matches:

Container 1
List Entries
  Entry[site] = CodeProject
  Entry[URL] = http://codeproject.org.cn
Select container number or 0 to return to previous menu
0

Main Menu:
0. Terminate
1. Create Container
2. Select Container
0

            

结论

本文展示了如何使用 IIOP.NET 从 J2EE 访问在 .NET 下创建和托管的对象。分布式应用程序的实现与仅使用 Java 的 RMI/IIOP 一样简单。显然,也可以反过来工作,将对象托管在 J2EE 上并从 .NET 远程访问它们:IIOP.NET 还包括一个生成器,用于在给定对象 IDL 的情况下为 .NET 创建代理。

IIOP.NET 允许在 .NET 下使用 CORBA 标准透明地访问远程对象。它与 .NET 的 Remoting 框架集成良好,因此,可以与任何其他现有的 Remoting 通道一起使用,而无需进行任何代码更改。

Remoting 和 RMI 是 .NET 和 J2EE 中用于在分布式对象系统中创建紧耦合交互的技术。WebServices 更适合松耦合系统。

链接和参考文献

项目和产品

技术

© . All rights reserved.