【问题标题】:OSGi bundle export versioningOSGi 包导出版本控制
【发布时间】:2019-04-22 18:25:13
【问题描述】:

我是 osgi 世界的新手,可能遗漏了一些东西,而且我在为 liferay 公开同一服务的不同版本时遇到了麻烦。

这是我正在尝试做的事情(对不起我的英语):

我写了一个服务,把它打包成一个bundle,并成功地部署在osgi上。我的 bnd.bnd 文件是这样的

Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 7.1.0
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServicesActivator
Export-Package: it.peernetwork.lr.pilot.testservices

而且,一旦打包,清单文件是这样的

Manifest-Version: 1.0
Bnd-LastModified: 1542646653910
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServic
 esActivator
Bundle-ClassPath: .,lib/pn--logger-7.1.0.jar,lib/pn--services-base-7.1
 .0.jar,lib/pn--prop-files-7.1.0.jar,lib/gson-2.8.5.jar,lib/pn--expand
 o-values-7.1.0.jar
Bundle-ManifestVersion: 2
Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 7.1.0
Created-By: 1.8.0_191 (Oracle Corporation)
Export-Package: it.peernetwork.lr.pilot.testservices;version="7.1.0"
Import-Package: com.liferay.expando.kernel.exception;version="[1.0,2)"
 ,com.liferay.expando.kernel.model;version="[1.1,2)",com.liferay.expan
 do.kernel.service;version="[1.1,2)",com.liferay.portal.kernel.excepti
 on;version="[7.2,8)",com.liferay.portal.kernel.model;version="[2.0,3)
 ",it.peernetwork.lr.pilot.testservices,org.osgi.framework;version="[1
 .8,2)"
Javac-Debug: on
Javac-Deprecation: off
Javac-Encoding: UTF-8
Private-Package: it.peernetwork.lr.pilot.test.services.impl,it.peernet
 work.lr.pilot.testservices.impl,it.peernetwork.lr.pilot.testservices.
 x,lib,it.peernetwork.lr.logger,it.peernetwork.lr.servicesbase,it.peer
 network.lr.propfiles,it.peernetwork.lr.propfiles.utils,com.google.gso
 n,com.google.gson.annotations,com.google.gson.internal,com.google.gso
 n.internal.bind,com.google.gson.internal.bind.util,com.google.gson.in
 ternal.reflect,com.google.gson.reflect,com.google.gson.stream,it.peer
 network.lr.expandovalues
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
Tool: Bnd-3.2.0.201605172007

此清单文件声明

Export-Package: it.peernetwork.lr.pilot.testservices;version="7.1.0"

我认为这是正确的。

一旦部署(成功),我会使用命令bundle __BUNDLE_ID__ 检查捆绑状态

pilot--test-services_7.1.0 [1014]
  Id=1014, Status=ACTIVE      Data Root=/home/ltrioschi/development/liferay-osgi/liferay-ce-portal-7.1.0-ga1/osgi/state/org.eclipse.osgi/1014/data
  "Registered Services"
    {it.peernetwork.lr.pilot.testservices.UselessService}={service.id=1607, service.bundleid=1014, service.scope=singleton}
  No services in use.
  Exported packages
    it.peernetwork.lr.pilot.testservices; version="7.1.0"[exported]
  Imported packages
    com.liferay.expando.kernel.exception; version="1.0.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
    com.liferay.expando.kernel.model; version="1.1.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
    com.liferay.expando.kernel.service; version="1.1.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
    com.liferay.portal.kernel.exception; version="7.2.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
    com.liferay.portal.kernel.model; version="2.0.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
    org.osgi.framework; version="1.8.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
  No fragment bundles
  No required bundles

然后我编写了一个需要此服务的 portlet。 bnd.dnd 文件是

Bundle-Name: it.peernetwork.lr.pilot.test-portlet
Bundle-SymbolicName: pilot--test-portlet
Bundle-Version: 7.1.0

Import-Package: \
    it.peernetwork.lr.pilot.testservices;version=[7.1.0],\
    *

-metatype: *

一旦部署,它会正确加载服务并毫无问题地使用它。

现在...我的问题是我需要新版本的服务,但我不想取消部署当前版本。

所以我写了新版本的服务,新的bnd.bnd文件是

Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 7.1.1
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServicesActivator
Export-Package: it.peernetwork.lr.pilot.testservices

(唯一的区别是Bundle-Version

一旦打包,清单文件的唯一区别就是 Export-Package

Export-Package: it.peernetwork.lr.pilot.testservices;version="7.1.1"

并且看起来它可以顺利部署在 osgi 上

g! lb pilot
START LEVEL 20
   ID|State      |Level|Name
 1014|Active     |   10|it.peernetwork.lr.pilot.test-services (7.1.0)
 1015|Active     |   10|it.peernetwork.lr.pilot.test-services (7.1.1)

但是使用命令bundle ___NEW_BUNDLE_ID___ 我得到了

No exported packages

而不是

Exported packages
  it.peernetwork.lr.pilot.testservices; version="7.1.1"[exported]

(我预期的)。这意味着(对我而言)捆绑包已部署,但没有任何服务被公开。

然后我以这种方式更新了我的 portlet 包 (bnd.bnd)

Bundle-Name: it.peernetwork.lr.pilot.test-portlet
Bundle-SymbolicName: pilot--test-portlet
Bundle-Version: 7.1.0

Import-Package: \
    it.peernetwork.lr.pilot.testservices;version=[7.1.1],\
    *

-metatype: *

(在Import-Package 中更改了版本)并部署在osgi 上。部署是正确的,但它仍然使用旧版本的服务包 (7.1.0),即使 Import-Package 声明版本 7.1.1。由于“缺少”请求的服务版本,它不会出错。

有人可以给我一些关于我做错了什么的提示吗?

提前致谢。


更新 1

build.gradle 文件中的依赖项已相应更新为bnd.bnd 中指定的版本。


更新 2

@quatax

更新后的 portlet 包的清单文件有 Import-Package: it.peernetwork.lr.pilot.testservices;version="[7.1.1]"(后面是所有其他必需的导入)...对我来说似乎是正确的...


更新 3

@Neil Bartlett(服务版本更新至 8.0.0)

我更新了pilot--test-services bnd.bnd 文件设置Bundle-Version: 8.0.0。 整个 bnd.bnd 文件是

Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 8.0.0
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServicesActivator
Export-Package: it.peernetwork.lr.pilot.testservices

清单文件是

Manifest-Version: 1.0
Bnd-LastModified: 1543316524201
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServic
 esActivator
Bundle-ClassPath: .,lib/pn--logger-7.1.0.jar,lib/pn--services-base-7.1
 .0.jar,lib/pn--prop-files-7.1.0.jar,lib/gson-2.8.5.jar,lib/pn--expand
 o-values-7.1.0.jar
Bundle-ManifestVersion: 2
Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 8.0.0
Created-By: 1.8.0_191 (Oracle Corporation)
Export-Package: it.peernetwork.lr.pilot.testservices;version="8.0.0"
Import-Package: com.liferay.expando.kernel.exception;version="[1.0,2)"
 ,com.liferay.expando.kernel.model;version="[1.1,2)",com.liferay.expan
 do.kernel.service;version="[1.1,2)",com.liferay.portal.kernel.excepti
 on;version="[7.2,8)",com.liferay.portal.kernel.model;version="[2.0,3)
 ",it.peernetwork.lr.pilot.testservices,org.osgi.framework;version="[1
 .8,2)"
Javac-Debug: on
Javac-Deprecation: off
Javac-Encoding: UTF-8
Private-Package: it.peernetwork.lr.pilot.test.services.impl,it.peernet
 work.lr.pilot.testservices.impl,it.peernetwork.lr.pilot.testservices.
 x,lib,it.peernetwork.lr.logger,it.peernetwork.lr.servicesbase,it.peer
 network.lr.propfiles,it.peernetwork.lr.propfiles.utils,com.google.gso
 n,com.google.gson.annotations,com.google.gson.internal,com.google.gso
 n.internal.bind,com.google.gson.internal.bind.util,com.google.gson.in
 ternal.reflect,com.google.gson.reflect,com.google.gson.stream,it.peer
 network.lr.expandovalues
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
Tool: Bnd-3.2.0.201605172007

。当我部署它时,它似乎没问题(启动并且状态为“活动”),但bundle ___ID___No exported packages

然后我更新了pilot--test-portletbuild.gradle 设置了正确的依赖版本(8.0.0)。它的清单文件说Import-Package: it.peernetwork.lr.pilot.testservices;version="[8.0,9)。当我部署这个包时它没有启动(状态“已安装”和错误Unresolved requirement: Import-Package: it.peernetwork.lr.pilot.testservices; version="[8.0.0,9.0.0)"


更新 4 -- -- 已解决 非常感谢@Neil。感谢您的提示,我解决了我的问题。正确的建议是this

显式声明

Import-Package: it.peernetwork.lr.pilot.testservices;version="[7.2,8)",\
        *

pilot--test-servicesbnd.bnd 文件中(自导入,具有合适的版本范围)使osgi 正确导出包并在需要时加载正确的类实例。

完整的bnd.bnd文件是

Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 7.2.0
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServicesActivator
Export-Package: it.peernetwork.lr.pilot.testservices

Import-Package: it.peernetwork.lr.pilot.testservices;version="[7.2,8)",\
        *

pilot--test-portletbuild.gradle文件中我只需要更新依赖版本

compileOnly group: "it.peernetwork.lr", name: "pilot--test-services", version: "7.2.0"

我尝试了 7.1.0、7.2.0 和 8.0.0 版本并且运行顺利。所有“服务”包都部署在 osgi 上。部署具有不同依赖版本的 portlet 包总是需要正确的服务。

再次感谢您。

【问题讨论】:

  • 你看日志了吗?部署您的 Test-Portlet 时是否有 org.osgi.framework.BundleException
  • 嗨@quatax。我在 tomcat 的日志中没有例外(它说包“已启动”),并且 portlet 包在 osgi 上有 Status=ACTIVE(由 bundle ___PORTLET_BUNDLE_ID___ 命令查看)。我不知道我可以检查更多的日志文件...如果还有更多的日志,请告诉我在哪里可以找到它们,以便我查看。
  • 这或多或少是一个疯狂的猜测。您更新的 Test-Portlet 的清单对导入的包有什么说明?你能把你的项目上传到某个地方(例如 GitHub)吗?查看整个项目(包括所有 gradle 文件)肯定会有所帮助 - 否则我将不得不继续猜测。
  • 我用所需的信息更新了答案。抱歉,我不能公开此代码,因为它是公司财产。我会尝试在这里为您提供您需要的所有信息,但我无法共享整个项目(不知道 java 文件是否与此上下文相关)
  • 因为你不能共享整个项目(而且没有人会对确切的代码感兴趣),我建议建立一个MCVE - 它不仅可以轻松共享,而且它是一个隔离手头的确切问题并了解基础知识的好方法。在相关说明中:我认为一个捆绑包依赖于另一个捆绑包的 exact 版本很奇怪。考虑使用语义版本控制并使您的 portlet 依赖于服务的 API。然后部署所需版本的服务。仅在绝对必要时更新主要版本

标签: osgi versioning liferay-7 bnd


【解决方案1】:

我建议从 bnd.bnd 文件中删除 Import-Package 指令以用于 pilot--test-portlet 捆绑包。没必要:bnd 会根据你代码中的实际需求生成你需要的所有导入。

您的原始包pilot--test-services 既导出又导入包it.peernetwork.lr.pilot.testservices。当您的捆绑包除了导出它之外还使用包本身时,这是正确的。因此,当您同时安装 v7.1.0 和 v7.1.1 时,v7.1.0 包将从其他版本导入包,而不是导出旧版本。 pilot--test-portlet 正确地从版本 7.1.1 导入。

换句话说,这里的一切都在按应有的方式工作。

【讨论】:

  • 尼尔您好,感谢您的回答。如果我删除Import-Package,清单文件中的导入将变为it.peernetwork.lr.pilot.testservices;version="[7.1,8)"。在这种情况下这没问题,所以我会这样做,但如果我想(可能在另一个项目中)引用特定版本的捆绑包,我的方式是正确的,对吧?无论如何,你很难过:pilot--test-portlet 正确地从版本 7.1.1 导入。 它没有。我在这些版本中有不同的日志消息,我可以知道pilot--test-portlet 使用的版本是 7.1.0。也许我错过了一些东西......
  • 你说你原来的 bundle Pilot--test-services 既导出又导入包 it.peernetwork.lr.pilot.testservices。我不明白您所说的“出口和进口”是什么意思……我只出口它……我如何进口?
  • 哦,是的,我明白了。 “较新”捆绑包正在从“旧”捆绑包中导入。这也是一个有效的结果。
  • 关于导入和导出,您可以在 pilot--test-services 的清单中看到这一点。 Bnd 生成了这个,因为你的包既导出包又在内部使用它。为了减少类空间碎片,从其他版本导入包比创建第二个导出更好。我看不出有什么好的理由同时导出同一个包的 7.1.0 版和 7.1.1 版!
  • 我检查了pilot--test-services的清单文件,并且在导入和导出中都有包。现在我知道了。谢谢你。 哦,是的,我明白了。 “较新”捆绑包正在从“旧”捆绑包中导入。这也是一个有效的结果:这意味着我没有“明确”的方式来“选择”我的 portlet 将使用的服务的哪个版本? OSGi 加载“随机”类,我只能取消部署旧版本或更改主要版本?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-17
  • 1970-01-01
  • 1970-01-01
  • 2016-09-15
  • 2018-08-08
  • 1970-01-01
  • 2020-07-29
相关资源
最近更新 更多