当前位置: 首页 > 工具软件 > Apache Aries > 使用案例 >

使用 Aries 构建 OSGi 应用程序

孙星鹏
2023-12-01

OSGi Alliance 包括一个由许多不同的贡献者组成的小组,他们负责管理和维护 OSGi 规范。OSGi 技术使用 Java™ 技术支持一个基于服务和模块的架构,应用于许多领先产品和框架中。

常用缩略词

  • API: 应用程序编程接口
  • IDE: 集成开发环境
  • JAR: Java 存档
  • XML: 可扩展标记语言

使用 OSGi 的一个常见产品示例就是 Eclipse IDE。Eclipse 插件在构建模块式应用程序中使用 OSGi 技术来实现其优势。Eclipse 有一个有用的 OSGi 控制台,允许通过安装和运行 OSGi 模块来测试它们。(本文中的示例使用这些 OSGi 工具来展示一些 OSGi 特性。)一些公共框架,比如 Spring,使用 OSGi 技术来支持可插入模块的创建和使用。

许多应用程序服务器,比如 IBM WebSphere® Application Server、Apache Geronimo、JBoss、Glassfish 和 Oracle®/BEA WebLogic,也使用 OSGi 技术。

可以通过两种方法使用 OSGi 技术来实现模块式的、面向服务的组件和特性。第一,OSGi 规范决定如何为 OSGi 捆绑包加载类,这是一个重要特性,允许模块拥有不同的库,而且这些库能够很好地相互协作。每个捆绑包都是沙箱化(sandboxed)的,意味着一个捆绑包中的日志库的版本不会与其他捆绑包中的同一产品的不同版本冲突。

第二,OSGi 规范要求模块的实现包含一些定义良好的接口和一个清单,这个清单包含关于内容的详细信息。这些接口和清单中的元数据的使用实现了松散耦合但紧密聚合的模块。构建实现它们的 Java 接口和 Java 类的一个最佳实践是将接口和实现放置到独立的捆绑包中。

OSGi 有许多知识可学。您可以通过 参考资料 中的链接了解更多信息,但对 OSGi 框架的一些目标先做一个小结有利于理解 Apache Aries 的用途和目标:

  • 降低复杂性。OSGi 由捆绑包组成。捆绑包(Bundles) 是完全模块化的,只通过服务接口相互通信。
  • 重用。由于 OSGi 捆绑包是完全模块化的,因此它们支持更好的重用。有些开源项目将它们的 Java 类打包到与 OSGi 捆绑包兼容的 JARs 中。
  • 易于部署。OSGi 框架提供一个标准化的 API,以支持 OSGi 实现使用一些工具来安装、启动和停止 OSGi 捆绑包。
  • 动态更新。由于 OSGi 捆绑包是模块化的且易于部署,因此无需重新启动应用程序即可进行更新。
  • 版本控制。 捆绑包的动态更新和沙箱化特性支持轻松部署和使用捆绑包的不同版本,而不会在 JARs 之间遇到冲突。类加载被沙箱化到每个捆绑包,因此日志记录框架这样的依赖项在捆绑包之间即使不同也不会导致问题。

了解 Aries

Apache Aries 的目标是支持企业应用程序的创建,将 OSGi 用作一个底层技术来将各部件绑定在一起。使用 Aries,可以使用 Java Transaction API (JTA) 和 the Java Persistence API (JPA) 这样的技术来构建不同的应用程序部件,并将它们公开为 OSGi 服务和模块。Aries 中的 OSGi 模块被局限于特殊的应用程序,以便它们在您使用 Aries 构建的应用程序外部不可见。参见 参考资料 中的链接,了解关于 Apache Aries 孵化器项目的更多信息。

OutOfMemory

在我的计算机上运行 Maven 目标时,我遇到了 OutOfMemory 错误。我通过键入 export MAVEN_OPTS=-Xmx265M,然后重新运行 mvn 命令解决了这些错误。

下载和安装 Aries

您可以以源代码形式下载 Aries,然后在本地构建它。Aries 站点上提供了关于以不同方式构建 Aries 源代码的说明(参见 参考资料)。本文中的示例使用 Maven 来构建 Aries 项目并将其代码导入 Eclipse。

要下载和安装 Aries,执行以下步骤:

  1. 在命令行使用 Subversion 命令检出 Aries 代码:

    svn export https://svn.apache.org/repos/asf/aries/
  2. 检出代码后,准备使用以下 Maven 命令下载代码:

    mvn clean
  3. 准备代码,以便使用以下 Maven 命令将代码导入一个 Eclipse 工作空间:

    mvn eclipse:eclipse
  4. 单击 File > Import,然后单击 General > Existing projects into Eclipse,将 Aries 项目导入 Eclipse。

构建一个服务

现在您已经下载和构建 Aries 代码并将其导入 Eclipse,您已经准备好基于 HelloWorld 示例创建自己的服务项目。样例服务对您给予的消息作出回显,但这种回显是反向的。这个示例展示如何将消息从客户端发送到服务端。

首先,为这个服务编写接口。理想情况下,OSGi 应用程序中的接口应该是独立于实现类的独立捆绑包(项目)。这种实践并没有增加 Eclipse 中的项目结构的复杂性,相反,它的好处是可以更轻松地交换出实现捆绑包。快速更改服务的实现是使用 OSGi 这样的技术(该技术实施一种模块式结构)的原因之一。

清单 1 显示了 EchoService 接口。该接口包含一个方法,该方法接受一个参数来对接口实现中的消息进行一些处理。它还包含一个initialize 方法。这个方法的目的是展示,当 OSGi 框架启动服务时是如何调用服务的。

清单 1. EchoService Java 接口
package com.example.echo.api;

public interface EchoService {

    void echoMessage(String message);
    
    void initialize();
    
}

接口编写好后,准备编写调用该接口公开的方法的客户端类。这个客户端类如 清单 2 所示。

清单 2. EchoServiceClient 类
package com.example.echo.client;

import com.example.echo.api.EchoService;

public class EchoServiceClient {

    private EchoService service;

    public void initialize()
    {
        String message = "My Message";
        service.echoMessage(message);
    }
    
    public EchoService getService() {
        return service;
    }

    public void setService(final EchoService service) {
        this.service = service;
    }
    
}

现在,为 EchoService 的实现添加一个类。为名为 com.example.echo.service 的服务实现捆绑包创建另一个项目,将一个项目引用添加到 com.example.echo.api 项目。

常用的命名约定包括将类命名为 EchoServiceImpl 的命名方法;我喜欢使用 DefaultEchoService — 根据服务的实现类型来命名。这个实现类将是 EchoService 接口的默认实现,如 清单 3 所示。

清单 3. DefaultEchoService 实现
package com.example.echo.service;

import com.example.echo.api.EchoService;

public class DefaultEchoService implements EchoService {

    public void echoMessage(final String message) {
        StringBuilder sb = new StringBuilder(message);
        sb.reverse();
        System.out.println(sb.toString());
    }

    public void initialize() {
        System.out.println(this.getClass().getName() + " is initialized.");
    }

}

下面,您必须编辑告知 Aries 如何发现和部署服务的文件。

部署服务

此时,您应该有一个客户端类、一个接口、以及一个实现接口的类。这三个类应该位于三个独立的项目中 — 每个项目中的一个文件。既然这些类已经定义,您现在可以创建告知 Aries 如何处理这些类的 XML 文件。

客户端配置文件如 清单 4 所示。

清单 4. 客户端配置文件
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
    <reference id="echoService" interface="com.example.echo.api.EchoService" />
    <bean id="echoClient" class="com.example.echo.client.EchoServiceClient"
        init-method="initialize">
        <property name="service" ref="echoService" />
    </bean>
</blueprint>

注意,这个客户端配置文件有一个对 echoService 的引用;此外,它还定义了 echoService 和这个 Java 接口的完全限定名。

服务器配置文件(如 清单 5 所示)与客户端配置文件类似。它将这个接口指定为一个服务,并包含一个对 bean 元素的引用,该元素包含服务实现的完全限定名。

清单 5. 服务器配置文件
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
    <bean id="echoServiceImpl" class="com.example.echo.service.DefaultEchoService"
        init-method="initialize">
        <property name="service" ref="echoService" />
    </bean>
    <service id="echoService" interface="com.example.echo.api.EchoService" />
</blueprint>

这里,可以看到,您通过在配置文件中定义实现类来获得了一些功能:无需更改任何代码即可更改实现,且客户端资源不会受到任何影响。

现在您已经将这些 XML 配置文件添加到两个项目 — 客户端和服务端项目 — 可以编译项目,将它们组装为 JAR 文件,并看看它们在使用 OSGi 控制台启动时的外观如何。

对于 OSGi 控制台,这个应用程序使用 Eclipse IDE 自带的控制台。或者,也可以使用 Apache Felix,这是另一个来自 Apache 的项目,它是一个 OSGi 容器的实现(参见 参考资料)。

一个简单的 Apache Ant 脚本(参见 清单 6)将编译所有这些项目,构建 JAR 文件,并将这些 JAR 放置到一个文件夹中。OSGi 控制台将从这个文件夹启动。

清单 6. 用于构建和打包这些捆绑包的一个简单 Ant 脚本
<project name="build.echo" default="build" basedir=".">
    
    <property name="src" value="src" />
    <property name="build" value="bin" />
    <property name="dist" value="dist" />
    <property name="workspacedir" 
        value="${basedir}/.." />
    <property name="api" 
        value="${workspacedir}/com.example.echo.api" />
    <property name="client" 
        value="${workspacedir}/com.example.echo.client" />
    <property name="services" 
        value="${workspacedir}/com.example.echo.services" />

    
    <target name="build">
        <javac srcdir="${api}/${src}" destdir="${api}/${build}"/>
        <javac srcdir="${client}/${src}" destdir="${client}/${build}"/>
        <javac srcdir="${services}/${src}" destdir="${services}/${build}"/>
    </target>
    
    <target name="package">
        <mkdir dir="${dist}" />
        <jar jarfile="${dist}/com.example.echo.api.jar" 
            basedir="${api}/build" />
        <jar jarfile="${dist}/com.example.echo.client.jar" 
            basedir="${client}/build" />
        <jar jarfile="${dist}/com.example.echo.services.jar" 
            basedir="${services}/build" />
    </target>
    
</project>

从 Eclipse 运行这个 Ant 脚本,使用目标构建来构建这些 JAR 文件。构建完成后,运行以下命令来启动 OSGi 控制台:

java -jar org.eclipse.osgi_3.5.0.v20090520.jar -console

OSGi 控制台运行后,可以通过在控制台上键入 ss 命令来查看这些模块的状态。清单 7 展示了一个 OSGi 控制台输出示例。

清单 7. 列示服务
osgi> ss

Framework is launched.

id      State       Bundle
0       ACTIVE      org.eclipse.osgi_3.5.0.v20090520
1       ACTIVE      org.eclipse.equinox.cm_3.2.0.v20070116
2       ACTIVE      org.eclipse.osgi.services_3.1.200.v20070605
3       ACTIVE      org.ops4j.pax.logging.pax-logging-api_1.4.0
4       ACTIVE      org.ops4j.pax.logging.pax-logging-service_1.4.0
5       ACTIVE      org.apache.aries.util_0.2.0.incubating-SNAPSHOT
6       ACTIVE      org.apache.aries.blueprint_0.2.0.incubating-SNAPSHOT
7       RESOLVED    com.example.echo.api_1.0.0
8       RESOLVED    com.example.echo.client_1.0.0
9       RESOLVED    com.example.echo.server_1.0.0

要启动任何一个服务,应使用 start 命令(例如,start 8)。

在 web 容器中使用 OSGi 服务

现在您已经创建了几个 OSGi 捆绑包并看到了它们的实际运行情况,下面我们看看 Aries 如何在一个 web 应用程序包中使用这些 OSGi 捆绑包。

您可以通过将运行 mvn install 任务时编译的项目组件(参见 参考资料 中下载二进制版本的链接)放置到一个目录中并启动 OSGi 控制台来启动一些 Aries web 应用程序。当 Aries 组件全部启动时,一个加载目录将被创建。

这些 web 应用程序从一些 OSGi 模块构建,这些模块打包在一个带有 .eba 文件扩展名的存档文件中。这些 .eba 文件拥有一个公共格式:如果您刚刚构建的 EchoService 接口拥有一个包含 Java servlets 的额外捆绑包,则这个 .eba 文件的内容将看起来如 清单 8 所示。

清单 8. 样例 .eba 文件
META-INF/APPLICATION.MF 
com.example.echo.api.jar 
com.example.echo.client.jar
com.example.echo.service.jar 
com.example.echo.web.jar

当 .eba 文件在一个 Aries 实例运行时被放置到加载文件夹中时,Aries 将解压这个 .eba 文件并启动文件中的捆绑包。要从 Aries 卸载一个应用程序,只需从加载目录移除该文件。

当您将一个 .eba 文件放置到加载目录中后,可以通过在一个浏览器中导航到这个 URL(比如 localhost:8080/com.example.echo.web/)来查看 web 应用程序。

Aries 自带的博客样例展示如何将 web 绑定放置在一起。此前运行的 mvn eclipse:eclipse 命令准备了将博客导入 Eclipse 的样例。这些样例项目如 清单 9 所示。

清单 9. 样例 web 捆绑包项目
org.apache.aries.samples.blog.api
org.apache.aries.samples.blog.biz
org.apache.aries.samples.blog.datasource
org.apache.aries.samples.blog.itests
org.apache.aries.samples.blog.jdbc.eba
org.apache.aries.samples.blog.jpa.eba
org.apache.aries.samples.blog.peristence.jdbc
org.apache.aries.samples.blog.peristence.jpa
org.apache.aries.samples.blog.web

深入挖掘

针对 Aries 的类似和补充项目和产品提供了许多方法来构建使用 OSGi 技术的应用程序。下面列举一些相关技术,可用于构建、管理并将 OSGi 组件分发到应用程序中。

Apache Felix 和 Apache Felix Karaf

Apache Felix 是一个核心 OSGi 框架实现。Felix OSGi 框架实现拥有许多子项目 — 例如,Apache Felix Karaf,它提供一个 OSGi 运行时,可以在其中部署 Aries — 用于添加一些组件来创建功能齐备的 OSGi 框架实现。在 参考资料 中了解关于 Apache Felix 和 Felix Karaf 的更多信息。

Apache ServiceMix

Apache ServiceMix 提供一个 Enterprise Service Bus (ESB) 且是 Felix Karaf 运行时的原始源。ServiceMix 使用 OSGi 组件构建,提供联合使用 OSGi 技术和面向服务架构(SOA)的能力。

WebSphere Feature Pack

Feature Pack for OSGi Applications and Java Persistence for IBM WebSphere Application Server 版本 7 实现了 Blueprint Container 规范,Aries 也使用这个规范(参见 参考资料)。Blueprint Container 负责以下功能:

  • 使用用于组件的 XML 配置文件
  • 实例化和初始化组件
  • 支持组件间的通信
  • 注册服务并查询服务

这个 Feature Pack 支持您将一些应用程序部署为 OSGi 捆绑包集合,这与 Aries 类似。

结束语

Aries 项目目前位于 Apache 孵化器中,但它的目标是支持开发使用 OSGi 技术的应用程序来构建模块式应用程序。OSGi 技术可用于构建 Java 服务和模块,这些服务和模块是真正模块化、可插入的组件。

您可以下载 Aries 并将其导入 Eclipse。从那里,您可以将本文中的样例应用程序用作模板来构建自己的服务,从而展示 Aries 的一些功能。

 类似资料: