OSGi enRoute – 2.2_8 – 依赖

在本章你将学到什么

在本章中我们将学习一个工程是如何依赖在工作空间内外部的其他工程的。我们将会介绍build path的概念以及在你工作空间中的仓库。

外部依赖

我们有很多值得骄傲的代码,但EvalImpl类并非其中之一。

为了保护我们的自豪感我们当然可以花费大量的时间来重写一个新的evaluator,但是如果已经有了很多人花费了无数的时间做了同样的事情,并且完成得非常漂亮而且能够免费供你使用,我们又何必重新发明轮子呢?

然而,这提出了如何在我们的构建中获得外部依赖的问题。首先我们需要搜索我们的本地仓库。在你的Eclipse的窗口的左下角列出了一个仓库清单:

20171210_001

现在在Maven中央仓库上有一个非常简单的解析器与我们的目的非常匹配:PARSII,并且它使用的是MIT协议。如果我们能够很容易地将它添加到我们的build path中,这岂不是非常棒吗?因此何不在仓库视图中搜索PARSII呢。

如果 查到的结果为空,我们该怎么办呢?那么我们可以在search.maven.org进行搜索。

20171210_002

如果我们点击对应的版本,我们可以获得下面的窗口:

20171210_003

我们现在应该将Apache Maven的dependency XML元素复制到剪贴板中。

如果查看cnf文件夹,那么我们会看到一个名叫central.xml的文件。双击此文件并且将剪贴板中的元素粘贴到dependencies 元素中。

BUG:很不幸refresh功能有一个Bug。要查看依赖,你必须在cnf工程的build.bnd文件中做一点小改动。这将会迫使Repository来正常地刷新其自身。

Repositories视图现在已经更新了,应该如下图所示:

20171210_004

添加到Build Path

我们首先应该打开com.acme.prime.eval.provider  工程中的bnd.bnd文件,并且打开Build选项卡。

20171210_005

你现在可以将 com.scireum:parsii拖放到Build Path之上,该清单上已经有了osgi.enroute.base.api。在你保存bnd.bnd文件之后,Eclipse类路径会自动被更新。

更新EvalImpl类

由于在你的Build Path中现在已经有了PARSII类库,我们可以在EvalImpl类中使用它。这个小巧的类库将会显著地简化我们的代码:

当我们保存这个类的时候,突然在Eclipse控制台上发现了一个错误,类似“could not resolve …”。这个大灰窗口中的提示刚开始可能会让你非常不爽,但由于我们常常会因为没有在控制台上看见错误信息而使得我们白费功夫。

回想起来,我们本可以预料这个错误,因为我们在代码中创建了一个外部依赖,在Build Path中我们已经添加了,但是在Runtime中并未添加。

打包

让我们来回顾一下打包魔法。下面来看看我们的Bundle是如何产生的:点击bnd.bnd文件并且选择Contents选项卡。显然由于这个Bundle引入了parsii.eval包,因此它无法被解析;这个包在运行时并没有提供服务的Bundle。

20171210_006

因此该Bundle看起来如下图所示:

20171210_007

现在我们有2种选择。我们可以将PARSII Bundle添加到运行时中或者我们可以将被导入的Bundle添加到我们自己的Bundle中。哪种方式最好呢?在本例中答案是显而易见的,因为PARSII 实际上不是一个Bundle;它仅仅是一个简单的JAR。你很容易就可以检验它。在Repository视图中的Central repository(查找parsii)下面选择PARSII Bundle。如果你双击该JAR包,会打开JAR查看器,并且会展示它的Manifest。

20171210_008

这个简单的Manifest并不是一个OSGi Manifest,因此,这不是一个Bundle。因此选项2,将这些包添加到JAR包之中是最佳选项。

回到Provider Bundle的Contents选项卡。如果你现在将parsii.eval包从Imported Packages清单中拖放到Private Packages清单之中,然后保存 bnd.bnd 文件,则你会看到一个新的import项替代了parsii.eval包:parsii.tokenizer。你现在也可以将这个包拖放到Private Packages清单之中,不过我们需要学习一些新的东西。

手动添加这些包会比较乏味,因此选择bnd.bnd编辑器的Source选项卡:

20171210_009

你现在看到的是底层的bnd.bnd属性文件;在bnd中所有的东西都是一个属性!我们现在可以替代Private-Package数据头中的子句并且使用类似parsii.*的通配符:

如果你现在保存bnd.bnd文件并且选择Contents选项卡,你会看到Import内容都消失了。我们的Provider Bundle现在看起来是这样的:

20171210_010

从Class Path中复制包到你的Bundle之中常常会给更多的传统开发者带来惊讶、恶心和呕吐。现在你必须相信我们知道为何我们打破这个禁忌。它实际上工作得非常良好。

玩起来

由于现在没有任何错误了,我们现在可以使用Gogo shell命令来测试我们的工作成果。我们现在不需要局限于单独的操作,可以自由发挥,寻找所有那些我们一直想知道却不敢问的(数学)答案:

现在你有很小的几率由于进行了一些不一样的操作导致没有出现对应的提示信息。如果遇到这种情况,请终止运行进程,进入bnd.bnd文件中的Run选项卡,然后再次点击Run OSGi。如果这样仍然没有解决问题,则请尝试后续步骤来进行一些调试。

此外,你可以尝试在Forum中寻找能帮助你的好人。

它是如何工作的?

Bnd的基本依赖模型是基于OSGi Bundle Symbolic Name (BSN)的。Build Path、Run Bundle以及一系列其他的Path和Bundle都在通过声明一个BSN和版本范围来在OSGi Bundle之中指定其依赖。这些规范最终都会被转换成Repository里位于文件系统中的真正的JAR文件。Repository会处理对一个BSN的请求,并且向bnd提供与该BSN相关的可用版本,将一个真实的BSN和版本转换为文件。Repository都是插件,也就是说它们不是bnd本身的一部分。编写一个连接到一些外部仓库的Repository是很容易的。被加载的Repository会展示在左下角的Repositories 视图中。

在enRoute工程中我们有如下Repository:

● 工作空间(Workspace) – Workspace repository 代表所有在工作空间中由工程构建的Bundle。你可以将这些Bundle作为依赖添加到你的工程之中。

● 发布(Release) – 这是最终我们的Bundle发布的Repository,你可以在./cnf/release文件夹中找到这个仓库。

● Maven中央仓库(Central )–这是通过一个POM文件来展示的Maven Central库的视图。你可以在./cnf/central.xml找到它。

由于PARSII JAR并不是一个Bundle,因此我们随后将PARSII中的包添加到了我们自己的Bundle之中。我们可以将其转换为一个Bundle,不过将它的类复制到你自己的Bundle之中是可行的,因为它们是被复制到了Private Package区域之中。私有类不会被暴露给外部并且不会跟其他Bundle产生冲突。确保在公开API中的对象不要出现在导出的包中。换言之,如果Eval接口引用了parsii.eval.Parsers类,那么我们不能将PARSII中的包添加到我们的Bundle中;这可能会导致非常令人不爽的OSGi错误。一般来说,bnd将会在这样的情况发生时提醒你。在本例中我们没有遇到问题是因为PARSII JAR完全被封装在了我们的Bundle之中。

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