4

我有一个 Maven 多模块项目,它有一个父 pom 项目和一堆模块。其中一个模块是“主模块”,其中包含所有库。所有其他模块都依赖于该模块并使用提供的库。

主模块是一个 Bukkit 插件,它将其他模块作为扩展加载。这些扩展都使用自己的类加载器加载,但加载的类在加载器之间共享,以便能够相互依赖。它们还能够依赖其他 Bukkit 插件,因为它们的父类加载器是 Bukkit 的 PluginClassLoader,它还在插件之间共享加载的类以允许交互。

这就是问题开始的地方:不同的插件可能使用同一个库,但该库的类可能会被不同的类加载器加载,这会导致 LinkageErrors 和其他问题。

我解决这个问题的想法是通过 maven-shade-plugin 重新定位主模块中的库。对于仅由主模块使用的库,这可以按预期工作。但是,其他模块使用的重定位库会导致运行时 ClassNotFoundExceptions,因为模块仍然搜索正常的包名称而不是重定位的包名称。然后我尝试将导入更改为重新定位的包,但我的 IDE (IntelliJ) 找不到这些类。

有没有人知道如何解决这个搬迁问题?或者在类加载问题上可能有不同的方法?

4

2 回答 2

3

5 年后在一个非常相似的情况下(Bukkit -> SpongeApi)我再次遇到了这个问题,但这次我找到了(可能只是令人满意的)解决方案:

  1. 主模块将其阴影版本作为主要工件,因此依赖项只能看到重新定位的类并且不知道原始类名。这在我们的例子中没有任何区别,因为主模块无论如何都是提供的依赖项,但它也可以防止消费者意外地直接使用重定位的类。IntelliJ 不关心重定位,因此它不知道新的重定位类。将着色版本附加为辅助工件(shadedArtifactAttached 选项设置为 true)使依赖项再次对依赖项可见。

  2. 依赖模块必须应用与主模块相同的重定位规则,因此插件将类名更正为运行时可用的类名。

这种方式 IntelliJ 不知道重定位,但它也不需要知道。如有必要,可以在父 pom 中配置重定位,以便在所有项目中保持一致的规则。

于 2018-04-01T20:05:54.993 回答
1

我遇到了几乎完全相同的问题(从这个问题的年龄来看)。尽管对于覆盖其他插件版本的库我没有更简洁的解决方案,但我确实有一个 IntelliJ 无法识别重定位类的解决方法。

为了阻止它抱怨,我将阴影 jar(带有重定位)作为 IntelliJ 库添加到目标模块。你可以这样做:

  1. File > Project Structure... > Modules > (target module) > Dependencies
  2. 使用 选择阴影罐Add (green +) > 1. Jars or directories...
  3. 您现在应该在库列表中看到阴影 jar

截图详细说明上面的解释

尽管乍一看似乎可行,但此解决方案的变通方法有一些注意事项:

  • 通过 Maven 的模块依赖项,代码仍然可以看到未重定位的类,如果您碰巧使用它们,您只会在使用 Maven 编译时看到。(您可以删除模块依赖项,但每次重新导入 pom 时都会读取它)
  • 如果您在 jar 文件名中包含版本号,则每次更改项目版本时都必须更新 jar 路径(解决方法:指定一个 static project.build.finalName
  • 添加新方法或更改签名时,需要重新编译库模块。(这可以通过为着色依赖创建一个单独的模块来解决 - 这实际上也可以解决文件名问题)
于 2014-08-19T00:22:34.920 回答