OSGi enRoute – 2.2_6 – 运行你的代码

在本节你将学到什么

在本节中我们将在一个真实的框架中运行之前章节中创建的工程。这需要我们选择运行时的初始需求(initial requirements)然后由bndtools将它们解析到运行bundle(run bundles)集合中去。然后我们可以运行框架。

运行什么?

当然我们可以运行当前的工程,不过这会遇到问题:

我们到底运行的是什么?看看我们已经创建的provider代码,我们不得不注意到它是一个非常懒惰的做法(懒惰真伟大!)Eval Provider实现了Eval服务在被调用之前处于等待状态。如果要让它做点什么引人注意的事情,我们需要为其添加一些行为。

在OSGi中,为了达到这个目的我们一般需要在 Apache Felix Gogo Shell.中创建一个命令。这个听起来很复杂但实际并不难,在取得了许可的前提下Gogo可以调用任何服务中的任何方法。

你可以通过添加一些特殊的service properties来发放许可。例如你仅需要将EvalImpl类的@Component注解修改为:

这些属性通过Gogo注册了test:eval命令。其中的scope(内容中的test部分)一般用来区分命令,避免歧义。(在本例中它的确非常有必要,因为在Gogo中已经有了一个eval命令,ok,这真是个烂点子!)

注意如果你复制上面的“property”定义并粘贴到你的代码中,eclipse会提示无法找到“Debug”类。此时可以将光标移到它旁边并按下Ctrl+空格键来自动导入必需的类。

Runtime Environment运行时环境

运行时环境定义了OSGi框架需要运行哪些东西,框架应该如何来配置,需要加载哪些支持性的bundle,还有其他参数如何配置。bnd.bnd编辑器的“Run”选项卡用来设置这些信息,因此双击bnd.bnd并选择Run选项卡。

20171203_001

“Run”选项卡由一组UI分部分组成,我们将会在后续的部分中讨论。

Core Runtime

Core Runtime 部分允许我们选择框架和执行环境。你应该将它们设置为org.eclipse.osgi (Eclipse Equinox) 框架并选择JavaSE-1.8 执行环境。执行环境一般指的是Java-SE的版本。

Run Requirements

确保所有的依赖准备就绪是软件开发过程中的烦心事之一。特别是在OSGi enRoute环境中我们并未依赖于具体的实现(我们的编译过程仅需依赖服务API),为我们的运行时查找匹配的Bundle集合可能会需要做一些工作。如果我们没有“Reslove”按钮就会遇到这个问题。

由于已经有了“Reslove”按钮,我们仅需要指定requirements而将体力活都留给bndtools。下面让我们来看看这些机制是如何运作的。

Run选项卡中包含了一个Run Requirements部分。这部分中包含了一个initial requirements列表。你可以将左边Available Bundles列表中的Bundle拖放到requirements列表中。我们仅希望运行我们自己的Bundle,因此初始的内容就足够了:com.acme.prime.eval.provider。这是我们当前Bundle的一个运行依赖,它已经默认设置好了(聪明!)。

在我们的代码中并未创建任何对Gogo shell的潜在依赖,因为我们仅仅是使用了属性。如果Gogo存在,则我们会提供一个命令,否则我们也不会受影响。然而,我们希望在运行时环境中运行Gogo,因为我们希望与我们的代码进行互动。为了让我们的运行时更加有趣,我们需要添加初始依赖org.apache.felix.gogo.shell,它会确保shell是可用的。

20171203_002

由于这个bundle使用了Declarative Service(DS),因此它至少需要一个DS的实现,你懂的。当你点击Reslove按钮时,bnd 解析器将会尝试创建一个满足所有依赖的bundle集合闭包。因此点击它吧!

一些常见的问题:

解析器会给出一个错误提示:missing requirement false。这个很诡异的信息通常是由一个API工程产生,原因是没有provider导出对应的包。你可以有如下几种选择:1-(推荐)在你的provider bundle中导出“com.acme.prime.eval.api”。2-从“com.acme.prime.eval.api” 的bnd.bnd文件的source选项卡中移除Require-Capability: compile-only 。

此时会弹出一个展示找到的bundle集合的窗口。否则至少会向你展示缺失了什么内容的诊断信息。如果一切顺利的话你将会看到如下对话框:

20171203_003

如果你接受了对应的结果,则该清单会变成此bnd.bnd文件的运行bundle清单。你可以通过点击bnd.bnd Run选项卡的右下角的Run Bundles部分来观察这个清单。

20171203_004

到现在为止,我们所做的工作都只是在内存中,你需要保存bnd.bnd文件来使其生效。

运行

在Run选项卡的右上角你将会看到一个Run OSGi和Debug OSGi按钮。点击其中的一个并享受你的第一个enRoute应用程序带来惊喜吧。你可以为自己感到骄傲!不过如果你找不到它,则可以看看窗口底部的Eclipse控制台输出。

20171203_005

当然我们会对21+21等于多少的终极问题会非常感兴趣:

有时候,你知道,生活是如此的美好……

更新

很快你会对加减法感到无趣。难道圣经上没有告诉我们做乘法吗?因此何不试试乘法和除法呢。打开Provider工程并且改变eval的实现,如下所示:

添加新的代码并保存EvalImple类,然后进入Gogo shell。嗯,你不需要停止框架,在OSGi的世界中我们是动态的。因此如果你有杀掉运行进程的坏习惯,你需要首先重启框架。点击bnd.bnd文件,选择Run选项卡并且点击Debug OSGi按钮。如果你不理解我在说什么,那么你的框架应该还在运行,你只需要进行更新既可。因此假设我们的Gogo shell如下图所示:

 

发生了什么呢?当我们改变源码的时候,IDE编译了类,并且触发了bnd构建对应的bundle。Launcher侦测到了一个新的Bundle并将其自动部署到运行的框架之中。这显然需要对我们的Bundle进行更新。实际上,你很少需要重启框架,你在IDE中改变的任何东西,包括bnd.bnd文件中的改变都会很快被部署到框架之中。

How Does it Work?

当你运行一个应用程序的时候,一个Launcher将会在一个远程进程中启动。这个Launcher会获得一个关于描述使用哪个框架,哪些Bundle需要被加载等信息的属性。在Launcher完成所有的初始化之后,它将会启动Bundle并启动对属性文件的监视。如果该文件发生了改变,它将会重新加载和计算这些属性,并将它们应用到运行着的框架之上。这对于大多数信息都有效,不过不是对所有信息都有效。

在bndtools进程中,我们会监听所有用于创建属性文件的信息的改变。如果检测到了一个改变,则启动属性文件将会被重新创建,然后触发对应的Launcher。

在这样动态的环境中进行开发是非常好的实践,即使你的系统是以非常静态的方式进行运行亦是如此。开发阶段的动态会暴露出很多潜在的问题,并且会使得你的代码变得更加健壮。这有点像飞行员。他们在训练时比真实情况的速度快上10%,那么当他们进行实际飞行时就会感觉到非常自然,因为这比他们平时适应的速度慢了太多了!

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