我正在使用Apache Karaf 4.1.1和Karaf Cellar。我写了两个包。第一个包提供ITrackerManager类型的服务。第二个包有一个引用ITrackerManager的组件。我的最终目标是见证第二个包中的组件成功获得对第一个包中的ITrackerManager服务的引用,该服务在不同的节点上运行。这是我探索分布式OSGi的全部内容。
安装第二个软件包时实际发生的情况是它已安装但由于缺少服务引用而无法激活。我必须错误地进行测试。 关于如何展示我的最终目标的任何想法; Node B上的bundle中的组件成功使用Node A上的服务?
到目前为止,我是如何运行测试的。
节点A
karaf@root()> cluster:node-list
| Id | Alias | Host Name | Port
--+-------------------+-------+--------------+-----
x | 159.4.251.58:5701 | | 159.4.251.58 | 5701
| 159.4.251.58:5702 | | 159.4.251.58 | 5702
节点B
karaf@root()> cluster:node-list
| Id | Alias | Host Name | Port
--+-------------------+-------+--------------+-----
| 159.4.251.58:5701 | | 159.4.251.58 | 5701
x | 159.4.251.58:5702 | | 159.4.251.58 | 5702
到目前为止一切顺利。我正在我的电脑上运行两个karaf实例。两个实例都互相看见。现在我想将第一个捆绑包安装到节点A上。为此,我将捆绑包安装到群集中,然后专门从Node B中删除它。
节点A
karaf@root()> cluster:bundle-install -s default mvn:myCompany/dosgi-example-part1/1.0-SNAPSHOT
karaf@root()> cluster:bundle-list default
Bundles in cluster group default
ID | State | Lvl | Located | Blocked | Version | Name
---+----------+-----+---------------+---------+----------------+--------------------------------------------------------------
0 | Active | | cluster/local | | 5.6.2 | System Bundle
...
67 | Active | | cluster/local | | 1.0.0.SNAPSHOT | Distributed OSGi Example Part 1
karaf@root()> cluster:service-list
Service Class | Provider Node
--------------------------+------------------
myCompany.ITrackerManager | 159.4.251.58:5701
| 159.4.251.58:5702
看起来还不错。我的捆绑包位于群集中,在节点A上是本地的(此时节点B),并且群集可以识别该服务,并且在节点A和节点B上都可用。现在从节点B中删除捆绑包。 / p>
节点B
karaf@root()> cluster:bundle-list default
Bundles in cluster group default
ID | State | Lvl | Located | Blocked | Version | Name
---+----------+-----+---------------+---------+----------------+-------------------------------------------------------------
67 | Active | | cluster/local | | 1.0.0.SNAPSHOT | Distributed OSGi Example Part 1
karaf@root()> bundle:list
START LEVEL 100 , List Threshold: 50
ID | State | Lvl | Version | Name
---+--------+-----+----------------+-----------------------------------------------
75 | Active | 80 | 1.0.0.SNAPSHOT | Distributed OSGi Example Part 1
karaf@root()> bundle:uninstall 75
karaf@root()> cluster:bundle-list default
Bundles in cluster group default
ID | State | Lvl | Located | Blocked | Version | Name
---+----------+-----+---------------+---------+----------------+--------------------------------------------------------------
67 | Active | | cluster | | 1.0.0.SNAPSHOT | Distributed OSGi Example Part 1
karaf@root()> cluster:service-list
Service Class | Provider Node
--------------------------+------------------
myCompany.ITrackerManager | 159.4.251.58:5701
优异。第一个捆绑包已从节点B中删除,但仍显示为在群集中。两个节点都同意我的服务现在仅在节点A上可用(因为捆绑包已从节点B中删除)。现在我将仅在Node B上加载我的第二个bundle。这是我遇到问题的地方。我没有使用cluster:bundle-install命令加载第二个bundle,因为我不希望它以Node A结束。所以我使用普通的bundle:install命令安装我的第二个bundle。这导致关于不满意的参考的错误。
节点B
karaf@root()> bundle:install -s mvn:otherCompany/dosgi-example-part2/1.0-SNAPSHOT
Bundle ID: 76
Error executing command: Error installing bundles:
Unable to start bundle mvn:otherCompany/dosgi-example-part2/1.0-SNAPSHOT: org.osgi.framework.BundleException: Unable to resolve otherCompany.dosgi-example-part2 [76](R 76.0): missing requirement [otherCompany.dosgi-example-part2 [76](R 76.0)] osgi.wiring.package; (&(osgi.wiring.package=myCompany)(version>=1.0.0)(!(version>=2.0.0))) Unresolved requirements: [[otherCompany.dosgi-example-part2 [76](R 76.0)] osgi.wiring.package; (&(osgi.wiring.package=myCompany)(version>=1.0.0)(!(version>=2.0.0)))]
karaf@root()> bundle:list
START LEVEL 100 , List Threshold: 50
ID | State | Lvl | Version | Name
---+-----------+-----+----------------+-----------------------------------------------------------------------------------------------------
76 | Installed | 80 | 1.0.0.SNAPSHOT | Distributed OSGi Example Part 2
就是这样。我只在NodeB上安装第二个bundle,期望它能够成功使用仅存在于Node A上的所需服务。不幸的是,这不会发生。相反,我得到错误消息,说明有未解决的要求。它似乎表现得好像DOSGI不可用。如果我在同一节点上安装两个软件包,则第二个软件包会激活而不会出现任何错误。您可能会有任何见解。
答案 0 :(得分:0)
我的问题是双重的。
通过DOSGI发送的东西需要可序列化。在我的例子中,我正在调用一个参与远程服务的方法。该参数是在通用API中定义的类类型。该类类型不可序列化。一旦我将其序列化,就会开始出现不同的错误。这让我想起......
适用普通名称空间规则。我将在下面详细说明。
我的API定义了两个接口。
该API捆绑包已安装到群集中,因此可在所有节点上使用。我的服务包有一个ITrackerManager的具体实现。当该捆绑包在节点A上本地安装时,cluster:service-list命令正确显示节点A具有ITrackerManager类型的服务。
我的客户端软件包有一个ITracker的具体实现,它引用了安装在Node B上的ITrackerManager.ITracker实例在其activate方法中做的第一件事就是调用ITrackerManager.addTracker(this)。应该发生的是节点B上的ITracker实例将自己提供给在节点A上运行的ITrackerManager。最初这失败了,因为ITracker不可序列化。一旦解决了,我就开始在节点A上看到classNotFound异常。
节点A试图在本地反序列化ITracker实例。它试图取消一个未在本地定义的具体类(TheyTracker)的deserailize,它只在客户端bundle中的Node B上定义。这失败了。
因此正常的命名空间规则适用。 即使节点B上的客户端捆绑包引用捆绑节点A中运行的服务,节点A中的服务捆绑也无法创建(即反序列化)仅存在于节点上的客户端捆绑包中的类的实例乙强>
我切换了我的界面,以便ITrackerManager方法不会采取ITracker争论。相反,它需要一个字符串。在DOSGi上调用该方法可以正常工作。
虽然我理解为什么存在这个问题,但这会破坏我希望与DOSGi一起使用的核心功能。我希望客户能够注册一个中央控制器,它将主动控制它们。这是行不通的,因为即使客户端实现了中央控制器正在寻找的接口,特定的序列化也会在中央控制器上失败。客户端具体类存在于中央控制器未知的命名空间中,因此客户端无法成功将自身传递给中央控制器。
这必须是在DSOGi中实现我正在寻找的东西的一种方式,而不会使每个多个客户端成为导出的DSOGi服务。有什么想法吗?