所有模块的Maven阴影重定位?

时间:2013-03-31 16:33:34

标签: maven bukkit

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

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

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

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

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

2 个答案:

答案 0 :(得分:2)

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

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

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

  3. 这样IntelliJ不知道重定位,但也不需要知道。如有必要,可以在父pom中配置重定位,以便在所有项目中使用一致的规则。

答案 1 :(得分:1)

我有几乎完全相同的问题(根据这个问题的年龄判断)。虽然我没有为图书馆提供更清晰的解决方案来覆盖其他插件。我有一个解决方法,IntelliJ无法识别重定位的类。

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

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

    screenshot detailing above explanation

    虽然它似乎乍一看,但解决方案解决方法有一些注意事项:

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