标题也可以是:
Maven和SBT组装插件之间有什么区别。
我发现这是一个问题,同时将项目从Maven迁移到SBT。
为了描述问题,我创建了一个带有依赖关系的示例项目,我发现它的行为有所不同,具体取决于构建工具。
https://github.com/atais/mvn-sbt-assembly
唯一的依赖是(sbt style)
"com.netflix.astyanax" % "astyanax-cassandra" % "3.9.0",
"org.apache.cassandra" % "cassandra-all" % "3.4",
我不明白的是,为什么mvn package
成功创建了胖罐,而sbt assembly
给出了冲突:
[error] 39 errors were encountered during merge
[error] java.lang.RuntimeException: deduplicate: different file contents found in the following:
[error] /home/siatkowskim/.ivy2/cache/org.slf4j/jcl-over-slf4j/jars/jcl-over-slf4j-1.7.7.jar:org/apache/commons/logging/<some classes>
[error] /home/siatkowskim/.ivy2/cache/commons-logging/commons-logging/jars/commons-logging-1.1.1.jar:org/apache/commons/logging/<some classes>
...
[error] /home/siatkowskim/.ivy2/cache/com.github.stephenc.high-scale-lib/high-scale-lib/jars/high-scale-lib-1.1.2.jar:org/cliffc/high_scale_lib/<some classes>
[error] /home/siatkowskim/.ivy2/cache/com.boundary/high-scale-lib/jars/high-scale-lib-1.0.6.jar:org/cliffc/high_scale_lib/<some classes>
...
答案 0 :(得分:4)
我还更新了my project的详细说明,因此您可能需要查看它。
遵循建议
你可以通过解压缩Maven产生的jar和SBT错误消息中的依赖jar来验证它的情况,然后检查Maven使用的.class文件。
我将fat-jars
和maven
生成的sbt
与
MergeStrategy.first
,显示了一些额外的文件MergeStrategy.last
,显示二元差异&amp;额外文件我已采取下一步措施并检查fat-jars
针对发现冲突的依赖关系sbt
,具体为:
maven-assembly-plugin
解决了jar
级别的冲突。
当发现任何冲突时,它会选择第一个jar
并忽略另一个中的所有内容。
sbt-assembly
混合所有class
个文件,在本地解析冲突,逐个文件。
我的理论会是,如果您使用fat-jar
制作的maven-assembly-plugin
有效,那么您可以
为MergeStrategy.first
中的所有冲突指定sbt
。
他们唯一的区别是,使用jar
生成的sbt
会更大,包含maven
忽略的额外类。
答案 1 :(得分:2)
似乎maven-assembly-plugin
通过选择其中一个来解决冲突等同于使用MergeStrategy.first
(不确定它是否等同于等等)jar-with-dependencies
时,以未指定的方式处理文件(自it only has one phase起):
根据程序集插件的2.5.2版,将文件添加到存档的第一阶段&#34;胜出&#34;。过滤仅基于存档内的名称完成,因此可以在不同的输出名称下添加相同的源文件。阶段的顺序如下:1)FileItem 2)FileSets 3)ModuleSet 4)DepenedencySet和5)Repository元素。
相同类型的元素将按照它们在描述符中出现的顺序进行处理。如果你需要&#34;覆盖&#34;前一个集合包含的文件,唯一的方法是从早期的集合中排除该文件。
请注意,在早期版本的程序集插件中,此行为略有不同。
即使其中一个冲突的文件适用于所有依赖项(也不一定如此),Maven也不知道哪一个,所以你可以默默地得到错误的结果。我的意思是,在构建时默默无闻;在运行时你可以得到例如AbstractMethodError
,或者只是错误的结果。
您可以通过编写自己的描述符来影响选择哪个文件,但是它非常冗长,并不等同于只写MergeStrategy.first/last
(和concat
/ {{ 1}}是不允许的。)
SBT插件也可以这样做:当你没有指定一个策略时默认为策略,但是,你可以默默地得到错误的结果。
答案 2 :(得分:0)
从 build.sbt 我可以看到他们在你构建中没有合并策略。此外,在“org.apache.cassandra”%“cassandra-all”%“依赖关系之后的 libraryDependencies Key 中有一个Rogue ”,“。 在您上面分享的链接项目的 build.sbt 中。
需要合并策略来处理所有重复文件以及jar和版本。以下是如何在构建中安装一个的示例。
assemblyMergeStrategy in assembly := {
case m if m.toLowerCase.endsWith("manifest.mf") => MergeStrategy.discard
case m if m.toLowerCase.matches("meta-inf.*\\.sf$") => MergeStrategy.discard
case "reference.conf" => MergeStrategy.concat
case x: String if x.contains("UnusedStubClass.class") => MergeStrategy.first
case _ => MergeStrategy.first
}
如果您的项目中没有子项目,您可以尝试编写一个简单的构建文件。您可以尝试以下build.sbt。
name := "assembly-test",
version := "0.1",
scalaVersion := "2.12.4",
libraryDependencies ++= Seq(
"com.netflix.astyanax" % "astyanax-cassandra" % "3.9.0",
"org.apache.cassandra" % "cassandra-all" % "3.4"
)
mainClass in assembly := Some("com.atais.cassandra.MainClass")
assemblyMergeStrategy in assembly := {
case m if m.toLowerCase.endsWith("manifest.mf") => MergeStrategy.discard
case m if m.toLowerCase.matches("meta-inf.*\\.sf$") => MergeStrategy.discard
case "reference.conf" => MergeStrategy.concat
case x: String if x.contains("UnusedStubClass.class") => MergeStrategy.first
case _ => MergeStrategy.first
}