【问题标题】:Deploying OSGi bundle starts another one部署 OSGi 包启动另一个
【发布时间】:2016-06-06 11:46:21
【问题描述】:

我在 Felix 中部署了一个用于 Sling 的 OSGi 包 (BundleA)。此捆绑包加载初始 Sling 内容,然后通过激活器对此内容执行一些操作(设置权限和排序节点)。效果很好,我使用 Felix maven-bundle-plugin 构建它,并在激活器中放置了一个捆绑事件侦听器:

@Override
public void bundleChanged(BundleEvent event) {
  if (BundleEvent.STARTED == event.getType()) {
    logger.info("Bundle A has started");
    BundleContext context = event.getBundle().getBundleContext();
  }
}  

但我有另一个捆绑包 (BundleB),在部署时会以某种方式触发 BundleA 的激活器。因此,代码再次执行,我不希望这样。

我没有找到任何关于“链接”捆绑包的文档。但我不熟悉 Felix/OSGi,所以我真的不知道要寻找什么。 BundleA 具有 BundleB 具有 Maven 依赖项,提供范围,因为它使用其中的一些常量。否则,我不知道有什么可以将他们两个联系起来。

任何关于什么可以触发另一个捆绑包的激活器的提示都会非常有助于理解它是如何工作的。如果需要,我可以发布更多代码/信息。谢谢

编辑:这是使用 CI 时引发问题的循环

  1. 部署 BundleB(sling-core):包含一个枚举类来存储常量
  2. 部署 BundleA (sling-content):加载 Sling 初始内容,并通过激活器使用 Jackrabbit API 自动设置权限和排序节点。此代码使用存储在 BundleA 中的枚举。
  3. 重新部署 BundleB(sling-core),因为推送了一些更改
  4. 问题:BundleA 也重新启动,然后重新进行权限和节点排序,这是我不想要的

【问题讨论】:

  • BundleA 也重新启动:BundleA 是否可能已连接到 BundleB(使用 Bundle B 中的类或它们之间定义的任何其他 Require-Capability)?
  • 是的,BundleB(核心包)包含一个枚举类来存储资源类型,BundleA(内容包)使用这个枚举来过滤JCR操作。关于 Require-Capability,这就是我在 MANIFEST 中看到的所有内容(由 Maven 捆绑插件生成): Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.7))"

标签: osgi apache-felix


【解决方案1】:

用很短的话:

如果

启动一个Bundle (A)
  • 设置为自动启动,并且bundle的启动级别低于framework的启动级别
  • 另一个使用包 A 中的类的包 (B) 已启动

我猜你的包 B 使用了包 A 中的类,所以包 A 将在包 B 启动之前启动。

您可能希望将捆绑包 A 分成两个捆绑包。您可以创建一个只包含 Activator 的新 Bundle,因此当 Bundle B 启动时,这个新 Bundle 不会自动启动(因为这个新 Bundle 中没有使用任何类)。

如果你想有更深入的了解,我建议你应该阅读第 4.3 章以及从这个 OSGi Core 规范链接的其他一些章节。

顺便说一句:我从来没有在我的任何项目中使用延迟启动策略或未启动的捆绑包。如果您开始使用像声明式服务这样的组件模型,并通过 ConfigAdmin 根据配置创建组件实例化逻辑,您可能不会再遇到这样的问题。您实际上没有必要实施 Bundle Activators。

编辑

根据问题中的新信息:

随着 Bundle B 的更新和更新,Bundle A 被重新连接到 BundleB,然后再次启动。您应该考虑将捆绑 B 分成两个单独的捆绑。一部分更恒定(例如:B-API),另一部分则不是恒定的(B-IMPL)。 Bundle A 应该只使用 B-API,当 B-IMPL 更新时,您将不需要重新布线。

首先它似乎让你工作更多,但这是真正的逻辑分离。我们有很多只包含 1-2 个类文件的包,但它们很稳定,并且很长时间没有新版本。

【讨论】:

  • 确实,我不确定激活器是实现我想要的最佳方式,但我从这里得到了这个想法:stackoverflow.com/questions/21380400/… 并且没有找到任何其他解决方案。基本上我想要的是在加载内容后进行设置(即仅在部署 BundleA 时),而不是在部署另一个包时。我正在使用声明式服务,但我希望每次我们的 CI 工具部署 BundleA 时自动执行这些操作以正确设置环境。
  • 从您的 cmets 我现在了解到我的 BundleB 重新启动了我的 BundleA,因为最后一个使用了 BundleB 中的类。虽然我理解你关于逻辑分离的解释,但我可能只是复制我的枚举类,因为我的内容包是加载和设置数据的临时包,一旦在生产中完成就不再使用。我会尝试看看它是否能解决我的问题
  • 我最终决定将我的内容标记为“已初始化”(在 JCR 中的节点上设置的属性),而不是移动所有内容。就像我说的,这个捆绑包只是用于内容迁移,所以没什么大不了的。但是谢谢,我现在对它的工作原理以及它们为什么连线有了更多的了解;谢谢。
【解决方案2】:

我认为您不应该在捆绑包级别执行此操作。相反,您应该使用组件和服务。为此使用声明式服务 (DS)。

基本计划是:

  1. Component1 执行您在 Sling 中所需的任何资源的设置。当这一切都完成后,它会发布一个服务……服务的类型并不重要,它可能只是一个没有方法的标记接口。

  2. Component2 在该服务上有一个强制引用(使用@Reference 注释)。

现在,Component2 在服务可用之前不会激活。因此,在 Component2 的activate 方法中,您可以确定资源已经正确设置。

顺便说一句,如果您在 Component1 中执行的任务很耗时,则不应在该组件的 activate 方法中同步执行它们(或在 BundleActivatorstart 方法中)事情!)。相反,您应该分拆一个线程并在那里执行它们。这避免了锁定 OSGi 事件系统和劫持属于启动器或其他包的线程。

【讨论】:

  • 我不确定我是否理解。为了 CI 的方便(每次重新部署我的内容包时设置所有内容),我希望我的代码自动执行,而不调用任何东西。这就是我使用激活器的原因。完成后,我不再需要这些服务,而且我实际上可以从 Felix 中删除捆绑包。我不必担心这里的性能,这个操作是一次性的,我只是在开发阶段多次重新部署捆绑包。所以基本上我希望在部署这个包时执行这个代码,而不是另一个。
  • 我想我明白了你的意思:我创建了一个 BundleActivated 服务(在你的示例中为 Component2),它带有对 NodeSorter (Component1) 的引用注释,该服务对 JCR 节点进行排序。在此服务中,我在我的方法上放置了一个激活注释来对节点进行排序。但它永远不会执行,即使所有服务都设置为“已注册”。我正在调查……但这听起来像你建议的那样吗?
  • 我做了这个,它更干净,但我有同样的问题(有线束)。
  • 这表明包导出的设计不佳。理想情况下,不要导出实现类,并将 API 包和实现包放在单独的包中。
  • 谢谢你,Neil,我现在明白了,我会分开接口和实现。但是,由于我们处于开发阶段,两者都会经常更新,我仍然不想在部署和启动后重新启动我的内容包。实际上,如果有一种简单的方法可以说“停止并取消部署自己”,我会去的。
猜你喜欢
  • 2016-11-01
  • 2011-03-27
  • 1970-01-01
  • 2015-02-15
  • 2013-03-09
  • 1970-01-01
  • 2013-06-26
  • 2014-06-04
  • 1970-01-01
相关资源
最近更新 更多