OSGi Alliance 包括一个由许多不同的贡献者组成的小组,他们负责管理和维护 OSGi 规范。OSGi 技术使用 Java™ 技术支持一个基于服务和模块的架构,应用于许多领先产品和框架中。
使用 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 的用途和目标:
Apache Aries 的目标是支持企业应用程序的创建,将 OSGi 用作一个底层技术来将各部件绑定在一起。使用 Aries,可以使用 Java Transaction API (JTA) 和 the Java Persistence API (JPA) 这样的技术来构建不同的应用程序部件,并将它们公开为 OSGi 服务和模块。Aries 中的 OSGi 模块被局限于特殊的应用程序,以便它们在您使用 Aries 构建的应用程序外部不可见。参见 参考资料 中的链接,了解关于 Apache Aries 孵化器项目的更多信息。
您可以以源代码形式下载 Aries,然后在本地构建它。Aries 站点上提供了关于以不同方式构建 Aries 源代码的说明(参见 参考资料)。本文中的示例使用 Maven 来构建 Aries 项目并将其代码导入 Eclipse。
要下载和安装 Aries,执行以下步骤:
svn export https://svn.apache.org/repos/asf/aries/
mvn clean
mvn eclipse:eclipse
现在您已经下载和构建 Aries 代码并将其导入 Eclipse,您已经准备好基于 HelloWorld 示例创建自己的服务项目。样例服务对您给予的消息作出回显,但这种回显是反向的。这个示例展示如何将消息从客户端发送到服务端。
首先,为这个服务编写接口。理想情况下,OSGi 应用程序中的接口应该是独立于实现类的独立捆绑包(项目)。这种实践并没有增加 Eclipse 中的项目结构的复杂性,相反,它的好处是可以更轻松地交换出实现捆绑包。快速更改服务的实现是使用 OSGi 这样的技术(该技术实施一种模块式结构)的原因之一。
清单 1 显示了 EchoService
接口。该接口包含一个方法,该方法接受一个参数来对接口实现中的消息进行一些处理。它还包含一个initialize
方法。这个方法的目的是展示,当 OSGi 框架启动服务时是如何调用服务的。
package com.example.echo.api; public interface EchoService { void echoMessage(String message); void initialize(); }
接口编写好后,准备编写调用该接口公开的方法的客户端类。这个客户端类如 清单 2 所示。
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 所示。
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 所示。
<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
元素的引用,该元素包含服务实现的完全限定名。
<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 控制台将从这个文件夹启动。
<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 控制台输出示例。
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
)。
现在您已经创建了几个 OSGi 捆绑包并看到了它们的实际运行情况,下面我们看看 Aries 如何在一个 web 应用程序包中使用这些 OSGi 捆绑包。
您可以通过将运行 mvn install
任务时编译的项目组件(参见 参考资料 中下载二进制版本的链接)放置到一个目录中并启动 OSGi 控制台来启动一些 Aries web 应用程序。当 Aries 组件全部启动时,一个加载目录将被创建。
这些 web 应用程序从一些 OSGi 模块构建,这些模块打包在一个带有 .eba 文件扩展名的存档文件中。这些 .eba 文件拥有一个公共格式:如果您刚刚构建的 EchoService
接口拥有一个包含 Java servlets 的额外捆绑包,则这个 .eba 文件的内容将看起来如 清单 8 所示。
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 所示。
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 是一个核心 OSGi 框架实现。Felix OSGi 框架实现拥有许多子项目 — 例如,Apache Felix Karaf,它提供一个 OSGi 运行时,可以在其中部署 Aries — 用于添加一些组件来创建功能齐备的 OSGi 框架实现。在 参考资料 中了解关于 Apache Felix 和 Felix Karaf 的更多信息。
Apache ServiceMix 提供一个 Enterprise Service Bus (ESB) 且是 Felix Karaf 运行时的原始源。ServiceMix 使用 OSGi 组件构建,提供联合使用 OSGi 技术和面向服务架构(SOA)的能力。
Feature Pack for OSGi Applications and Java Persistence for IBM WebSphere Application Server 版本 7 实现了 Blueprint Container 规范,Aries 也使用这个规范(参见 参考资料)。Blueprint Container 负责以下功能:
这个 Feature Pack 支持您将一些应用程序部署为 OSGi 捆绑包集合,这与 Aries 类似。
Aries 项目目前位于 Apache 孵化器中,但它的目标是支持开发使用 OSGi 技术的应用程序来构建模块式应用程序。OSGi 技术可用于构建 Java 服务和模块,这些服务和模块是真正模块化、可插入的组件。
您可以下载 Aries 并将其导入 Eclipse。从那里,您可以将本文中的样例应用程序用作模板来构建自己的服务,从而展示 Aries 的一些功能。