我很想知道Intellij如何解决依赖冲突?让我解释一下我的情况。我应该处理spring boot应用程序。它使用Maven。IntelliJ可以毫无问题地构建和运行应用程序,但当我制作一个jar文件时,
mvn clean package
并运行jar文件
java -jar xxx.jar
我面对的是java.lang.NoSuchMethodError
。依赖关系上的一些冲突导致了这种情况,并且我的应用程序使用了错误版本的jar文件。我想知道IntelliJ如何找到包含该方法的正确jar文件,同时它使用相同的pom.xml,我在与mvn命令一起使用时遇到错误。是否可以找到IntelliJ使用的每个jar文件的哪个版本?(我想用这个来纠正pom文件)
感谢
归根结底,运行时和编译时之间有很大的区别。
编译代码(如mvn package
)和编写代码(如中,IntelliJ正在做什么来确保您的编辑体验良好;为您使用的所有库自动完成对话框,如果您试图调用不存在的方法,则会出现错误,等等)是一回事(让我们称之为"编写时间")。
与java -jar xxx.jar
一样运行代码是完全不同的。
maven和您的依赖项列表是写时的事情。因此,maven和intellij知道在哪里查找依赖项,但当您运行java -jar xxx.jar
时,不知道在哪里查看,因此,您的依赖项找不到,因此,出现了NoClassDefFoundError
。
这是因为maven创建的jar文件只包含您的代码,它与您的maven文件完全断开连接(当您运行代码时,根本不会查找您的mavin内容),并且它不包含您的依赖项。
你必须单独发货。这个问题有三种解决方案:
- 首选解决方案:jar文件包含一个所谓的manifest,它告诉JVM例如该jar文件中主类的名称。它还可以包含类路径(事实上,这是使用
java -jar
运行jar文件时检查的唯一类路径;不能指定-classpath
参数)。这允许您部署应用程序,以便您的应用程序安装看起来像:
/usr/local/projects/YourApp/main-app.jar
/usr/local/projects/YourApp/dep/guava.jar
/usr/local/projects/YourApp/dep/mysql-jdbc-connector.jar
/usr/local/projects/YourApp/dep/jdbi.jar
等等,要运行此应用程序,只需运行main-app.jar
即可。这需要main-app.jar的清单包含以下条目:
Class-Path: dep/guava.jar dep/mysql-jdbc-connector.jar dep/jdbi.jar
运行jar时,Class-Path
条目在空格上进行拆分,然后根据包含main-app.jar
的目录查找每个条目。通过单独运送jar,可以很容易地单独更新或替换它们,并且部署新版本要快得多(您只运送更改过的jar,而不是所有的jar)。许多应用程序都有数百MB的dep,而它们自己的jar最多只有几MB,这会产生很大的差异,例如,当将dep从开发机器推送到测试服务器时!)
这就引出了一个问题:如何让maven将该类路径条目放入输出jar文件的清单中?maven-jar-plugin
可以完成这项工作-有关更多详细信息,请参阅此答案。
- 在deps中进行着色(也称为striping、fatjar或bigjar)
这是一个概念,即获取所有dep,重写它们的名称以避免版本冲突,然后创建一个包含所有内容的巨大jar文件。它有一个相当大的缺点,那就是慢得多,尤其是当你需要把它推到另一个系统进行测试时。使用阴影插件来做到这一点。
- 不要使用
java -jar
java -jar x.jar
无法工作,除非jar文件的清单中有一个类路径条目,或者包含它需要的每个dep。但是,您也可以像这样运行您的java代码:java -cp main-app.jar:dep/guava.jar:dep/jdbi.jar:/dep/other-deps-here com.foo.YourMainApp
。这并不方便,但您可以编写一个shell脚本或类似的脚本。这不是一个很像java的解决方案,我不推荐它