我们需要使用Maven来构建一个jar,使其包含所有依赖项,而且还要将所有那些依赖项重命名(重定位)。

假设我们自己的软件包都以“com.mycompagny.projectx.*”开头。我们希望项目依赖项将其软件包重命名为以“embedded”开头,而不是我们自己的类。

例如,使用maven-shade-plugin,我无法实现:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.3</version>
    <configuration>
        <shadedArtifactAttached>true</shadedArtifactAttached>
        <createDependencyReducedPom>true</createDependencyReducedPom>
        <artifactSet>
            <includes>
                 <include>*.*</include>
            </includes>
        </artifactSet>
        <relocations>
            <relocation>
                <pattern>*</pattern>
                <shadedPattern>embedded.</shadedPattern>
                <excludes>
                    <exclude>com.mycompagny.projectx.*</exclude>
                </excludes>
            </relocation>
        </relocations>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
        </execution>
    </executions>
</plugin>

此处<pattern>*</pattern>无效。另外,如果我使用<pattern></pattern>(空字符串),那么所有内容都将重定位到“嵌入式”包中,甚至包括资源(“META-INF”目录也是如此)!当然,我们希望资源停留在 jar 的根部。

我猜我们可以创建多个<relocation>元素,每个依赖项包一个,但是这将需要大量工作:<relocation>com</relocation><relocation>net</relocation><relocation>javax</relocation>等。

关于如何在不影响我们自己的类,资源和“META-INF”目录的情况下轻松地在uber jar中重新定位所有依赖项的想法?

最佳答案

更新:此解决方案实际上并不起作用,请仔细阅读。

通过查看maven-shade-plugin的源代码,我找到了一个解决方案!它似乎没有在任何地方记录,但是您可以将 <rawString> 参数添加到<relocation>元素中,以便将<pattern><shadedPattern>视为正则表达式模式,而不是程序包/文件名。

然后,maven-shade-plugin代码使用类似以下内容的代码:

path.replaceAll(pattern, shadedPattern)

处理那些模式。

例子 :
<relocation>
    <pattern>^([^/]*\.properties)$</pattern>
    <shadedPattern>embedded/$1</shadedPattern>
    <rawString>true</rawString>
</relocation>

这是一个虚拟示例,该示例重定位了根目录中的所有.properties文件。我敢肯定,使用这种技术,将有可能精确地控制要重定位的内容以及如何进行重定位。

这是一个更好的示例,它可以满足我的需要(尽管仍然需要进行一些测试):
<relocation>
    <pattern>^(?!(com/mycompagny/|META-INF))(.*/.*)$</pattern>
    <shadedPattern>embedded/$2</shadedPattern>
    <rawString>true</rawString>
</relocation>

更新:可悲的是,最后一个模式意味着所有使用的东西都将被重命名,除了“com.mycompagny”和META-INF文件夹。问题是,像java.lang.Object这样的东西将被重命名!当代码运行时,将抛出诸如此类的异常:
java.lang.ClassNotFoundException: embedded.java.lang.Object

09-26 05:43