OSGi enRoute – 2.3_2 – API 工程

你将会从本章中学到什么

在本章中我们将创建一个为简单的表达式计算器API。它将会告诉你如何创建一个API工程,如何命名一个工程,以及如何在工程内部进行浏览。另外我们将会告诉你如何对Package进行版本控制。

20180128_201

确认你在如下文件夹中:

创建一个POM

你需要在osgi.enroute.examples.eval 文件夹中创建一个api文件夹。在这个文件夹中我们创建一个pom.xml文件。

这个POM应该如下所示:

接下来定义父pom,我们可以从该POM中继承很多信息。

.api – 仅用于API工程我们从父POM中继承了version和groupId,因此我们仅仅需要指定artifactId即可。artifactId会作为Bundle Symbolic Name。在OSGi enRoute中,(强烈)建议artifactId的最后一段按下面的惯例来进行命名:

● .provider, adapter –一个实现工程

● .application – 一个应用程序工程。该工程会将很多组件绑定在一起并且将它们参数化。

● .test – 一个OSGi测试工程,这些测试将会在框架内部运行。

Bundle的名称为:

这个Bundle会生成一个JAR,其中包含了API代码和OSGi元数据。我们因此需要将它以JAR的形式进行打包。

还需要编写必要的文档说明:

运行命令mvn verify来校验你的pom文件。

源码

我们想创建一个计算表达式的组件。首先我们需要定义对应的契约。现在服务契约可以是一个接口。在 osgi.enroute.examples.eval/api文件夹中的 src/main/java/osgi/enroute/examples/eval/Eval.java文件中定义如下内容:

版本控制

OSGi的Package可以在Bundle之间共享,它们都有一个版本。尽管这对于习惯了使用Maven版本控制的开发者来说非常复杂,但是不要担心。Bnd Maven 插件大大简化了版本管理的工作。

因此,我们需要将一个包含了版本的文件放到Package文件夹中。我们通过在Package中使用注解来完成这个任务。因此,请在Package文件夹中创建一个带有如下内容的packageinfo.java:

在对Package进行导出(Export)操作的时候,Bnd插件将会选择这个版本并将其添加到Manifest之中。当你改变了Package的内容之后,你应该改变对应的版本号。

语义化版本控制

OSGi强烈建议进行语义化版本控制。语义化版本控制的规则会基于兼容性要求改变版本号的一部分。语义化版本控制对于Package的版本管理非常重要,你需要严格遵循它的规则。(有一个插件可以验证你是否违背了Java二进制兼容模型的规则。)在OSGi中一个版本号由4部分组成:

● 主版本号(Major)–第一个数字。如果它发生了改变则意味着与前一个版本不再兼容。

● 副版本号(Minor) – 第二个数字。如果它发生了改变则意味着provider不再兼容,但对于consumers来说还是兼容的。

● 小版本号(Micro) –第三个数字。如果它发生了改变则意味着没有在二进制或语义上发生改变,例如可能改进了注释。

● 限定符(Qualifier) – 最后的数字。不同的构建会发生改变。

Provider和Consumer 类型

在这个API中,任何将会实现Eval接口的参与者都会被视为Provider。一个Provider必须完全实现几乎没有向后兼容性的契约,这与这个API的Consumer不同。在版本中有任何影响public API的改变都必须对Provider的Bundle的重新构建。也就是说,如果我们的版本号变成了1.1,则我们需要确认实现了1.0的Provider不再兼容。

显然要确保使用正确的版本范围是一个噩梦。通过在接口上添加注解我们会对Provider提供很大的帮助:

Bnd Tool现在将会自动确保接口的实现者都使用语义化版本控制来导入带有一个副版本范围约束的Package,例如[1.0,1.1) ,因为它们会被视为Provider。

由你的API的Consumer实现的接口(通常是类似Listener的接口)可以使用 @ConsumerType来进行注解。无论如何,这个是默认情况。

如果你发现这很难使用,这并不奇怪,因为这是一个很复杂的领域。我们后续将会回顾这些内容,所以如果你不能马上理解也没关系。

Bnd文件

Bnd插件提供了OSGi元数据,并且让我们保持能够放心。在父POM中定义的插件需要一个bnd.bnd文件,该文件与POM文件放在同一个文件夹中。在本例中,我们提供了API,因此需要Export对应的Package。

Bnd.bnd文件是一个properties文件,适用同样的规则。注解可以使用带有#的文本行。每行的第一个单词是对应的key,然后是一个空格,一个“:”或“=”作为分隔符。后续的内容是Value,并且会过滤到任何前置的空格。

首字母大写Key会被添加到Manifest中,其他的key是宏指令,可以在任何地方以${key}的语法来使用。

名为Bundle-Description的key用于描述当前Bundle。

Compile Only

如果你查看bnd.bnd文件,你会发现这个API Bundle是Compile only的:

Compile only的原因在于最佳实践表明Provider应该Export它的API。关于这个话题曾经有过无数的讨论和不同的结论。然而,一个API的Provider与其提供的API的版本是非常紧密相关的。几乎API中的任何改变都会需要Provider进行改变,与API Consumer不同,它们没有向后兼容性。因此,从Provider中Export API会使得整个系统复杂性会降低些。

Export

在工程中的所有Package会自动添加到Bundle之中。默认情况下,这些包都是private的。Export-Package数据头(Header)会告诉bnd将为 osgi.enroute.examples.eval.api 这个Package增加Export Header。

构建

我们的osgi.enroute.examples.eval/api 文件夹应该看起来如下所示:

你可能会有一个target文件夹,Maven会将临时文件放到这个文件夹中。要update/create这个target文件夹我们需要再次运行mvn install。

在target文件夹中还有一些其他的文件。因为我们进行了一次install,我们还会把JAR文件复制到Maven的本地仓库中,位于

如果我们已经将bnd安装成了一个命令行工具,则你可以查看Manifest:

你可以通过使用print选项来打印更多的信息,你可以通过bnd help print来查看对应的选项。

它是如何工作的?

当我们运行Maven时,bnd插件将会分析类文件并使用在这些文件中的信息(包括注解)来生成一个Manifest。Bnd tool内置了很多OSGi知识,它可以给出很多错误和警告来提示问题。

这个插件会将Manifest和其他文件放到 target/classes 文件夹中。随后这个文件夹会由Maven Jar插件打包到一个JAR中。

在M2Eclipse中,bnd插件会在每次改动后运行,但JAR插件并不会每次运行。因此classes文件夹会被更新而JAR文件不会。你需要运行maven install来在本地仓库中创建JAR文件。

我们完成了什么?

你刚刚使用Maven创建了你的第一个Bundle!你已经创建了一个Service API Bundle,我们可以在其他工程中使用它进行编译,不过它不能在运行时使用。

我们学习了一些关于语义化版本控制规则和如何在OSGi中提供Packge版本管理的内容。

 

打赏一下
支付宝
微信
除非注明,博客文章均为原创,转载请标明文章地址
本文地址: http://www.javafxchina.net/blog/2018/01/osgi-enroute-0203_2/
百度已收录