【问题标题】:java.util.ServiceConfigurationError Provider not a subtype while using OSGi bundlejava.util.ServiceConfigurationError 使用 OSGi 包时提供程序不是子类型
【发布时间】:2019-06-28 04:15:30
【问题描述】:

我正在创建一个 Liferay 7.1 OSGi 包,其中包含一些外部依赖项。考虑到时间,我们选择将外部 JAR 嵌入到我们的 OSGi Bundle 中。我设法创建了一个 bnd 文件,其中包含所有 ElasticSearch 依赖项,并将它们放在包类路径中。我使用了来自 github (https://github.com/liferay/liferay-portal/blob/master/modules/apps/portal-search-elasticsearch6/portal-search-elasticsearch6-impl/build.gradle) 的源代码和 bnd.bnd 文件来检查导入的内容。

激活捆绑包时,抛出异常:

The activate method has thrown an exception 
java.util.ServiceConfigurationError: org.elasticsearch.common.xcontent.XContentBuilderExtension: Provider org.elasticsearch.common.xcontent.XContentElasticsearchExtension not a subtype
    at java.util.ServiceLoader.fail(ServiceLoader.java:239)
    at java.util.ServiceLoader.access$300(ServiceLoader.java:185)
    at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:376)
    at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:404)
    at java.util.ServiceLoader$1.next(ServiceLoader.java:480)
    at org.elasticsearch.common.xcontent.XContentBuilder.<clinit>(XContentBuilder.java:118)
    at org.elasticsearch.common.settings.Setting.arrayToParsableString(Setting.java:1257)

XContentBuilderExtension 来自 elasticsearch-x-content-6.5.0.jar, XContentElasticsearchExtension 类包含在 elasticsearch-6.5.0.jar 中。两者都是包含的资源,并已放在类路径中。

Activate 方法在我的另一个 jar 中初始化一个 TransportClient,因此它发生在激活时;)。

编辑:

我注意到第一次安装此错误或门户重新启动时不会发生此错误。所以它只发生在我卸载并重新安装捆绑包时。 (这是我非常喜欢的功能!)。也许是一个愚蠢的想法。但会不会有一些“悬线”?捆绑包没有正确安装,或者 TransportClient 仍然存在?我正在检查这个。欢迎任何提示!

编辑 2:

我担心这是 SPI 和 OSGi 之间的不兼容?我已经检查过:High Level Rest Client 也有同样的问题。 (但随后有另一个扩展名)。我将尝试使用 Low-Level Rest Client。这应该可行,因为我猜依赖最少。我仍然很好奇为什么存在不兼容。我当然不是 OSGi 方面的专家,也不是 SPI 方面的专家。 (是时候学习新东西了!)

【问题讨论】:

  • 问题:为什么要将代码嵌入到自己的包中,而这些包已经在 liferay 中可用?见i.imgur.com/Rra4dAa.png
  • 因为我的外部依赖本机使用 ElasticSearch。 Liferay 不导出弹性包。弹性包不能通过 OSGi 获得。但如果我错了,请纠正我。 :)
  • 我不是 osgi 大师,但是为什么不使用现有的 portal-search-elasticsearch6-impl 包,复制一份,更改 bdn.bdn 并导出你想要的,给它一个新版本并部署 jar...?
  • 嗯,这正是我不愿意做的。触摸 Liferay 的内部包来修复我的。这真的是非常糟糕的做法,我建议你永远不要这样做。在您的情况下,无论何时更新捆绑包,您都应该手动更新类。除了 Elastic Dependency 之外,我们的 bundle 与现有的 portal-search-elasticsearch6-impl 有 0 个相似之处。OSGi 的全部意义在于 bundle 有自己的类路径,甚至可以部署多个版本的相同的依赖。我不会为自己滥用现有的捆绑包......
  • 好的,Kornelito,很清楚

标签: elasticsearch liferay osgi osgi-bundle embedded-osgi


【解决方案1】:

您可以在一个 Java 应用程序中拥有 2 个弹性搜索连接,Liferay 默认情况下不公开它所拥有的连接。

一种解决方法是重建 Liferay ES 连接器。这没什么大不了的,因为您不需要更改代码,只需更改 OSGi 描述符即可公开更多服务。

我在一个 POC 项目中做到了,并且工作正常。棘手的事情是重建 Liferay jar,但 Pettry 用他的谷歌搜索博客文章解释了这一点。 https://community.liferay.com/blogs/-/blogs/creating-a-google-like-search(这是一个系列,但在新的 Liferay 博客中导航有点困难,但 Google 可能会提供帮助)无论哪种方式都很好地记录在这里 https://github.com/peerkar/liferay-gsearch

唯一需要做的就是在导出部分的 bnd.bnd 文件中添加org.elasticsearch.*。然后,您将能够使用本机弹性 API。

【讨论】:

  • 这与 cmets-section 中的 Daniele Baggio 的答案几乎相同。我知道这是可能的,但我更愿意在我自己的代码中保留更改。我不愿意重建默认的 Liferay ES 连接器。他们所做的每一次更改,我都将负责重建该模块。顺便说一句,重新部署那个连接器,也需要重新启动系统,据我说这与 SPI & OSGi 不兼容有关。我添加了赏金,因为我想了解更多关于为什么它不起作用的信息,因为我目前已经实现了这个。为什么会发生这种异常?
  • 我认为问题更多地与 ES 连接器有关,然后是 Liferay 或 OSGi,尽管我上次玩它时也感到惊讶,因为它不起作用。旧客户端的问题在于 ES 如何连接到集群。但我希望 HLRC 对我来说与实际的 ES 服务器更加断开。你看过 ES 的源代码吗?
  • 你肯定是对的。我注意到 Liferay 连接器也有这个问题。每当重新部署连接器时,我都会收到一条日志消息,指出连接器将在下次启动时安装。 (可能是为了解决这些问题。)。 HLRC 包还包含一些 SPI。让这正是问题所在。
【解决方案2】:

似乎 OSGi 使用您的包来解决来自另一个包的依赖关系,可能是在系统启动时使用您的包来解决包的情况。

看症状:开机或重启时不会出现。它也不是一个子类型。

当 OSGi 使用该捆绑包解决依赖关系时,它会保留一个副本,即使您删除它也是如此。当捆绑包返回时,另一个捆绑包之前使用的包可能仍然存在,并且您可能会遇到这样的情况,即使用的类有两个版本,来自不同的类加载器,这意味着它们不是同一个类,因此不是一个亚型。

只公开必要的,以尽量减少这种影响。仅在需要导入时才导入。如果您正在使用 Liferay Gradle 配置将捆绑包包含在其中,请停止 - 这是一种糟糕的包含方式,因为它暴露了很多内容。如果使用 bnd 文件来包含资源并为 adicional 类路径位置创建条目,则不要在没有必要时公开。如果您有多个捆绑包使用一个作为依赖项,请确保它们使用的版本以及是否从有问题的类交换对象,如果有,则需要格外小心。

PS:您可以在导出和/或导入时包含属性,以便更具体并避免使用来自错误来源的包。

【讨论】:

    猜你喜欢
    • 2019-09-14
    • 2021-01-02
    • 2017-06-28
    • 2015-03-14
    • 1970-01-01
    • 1970-01-01
    • 2016-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多