用`mvn clean package`替换`mvn clean install`之后的奇怪行为

时间:2018-06-30 16:26:26

标签: java maven

我的项目有两个依赖项,每个依赖项都有com.Foo类。区别在于第二个方法具有方法setVersion

dependency_1  com.Foo does not have method setVersion

dependency_2  com.Foo.serVersion
  • 使用mvn clean install构建.war文件时可以。
  • 当我将其更改为mvn clean package时,它可以编译成功。但是在运行时,会抛出NoSuchMethodError

我知道导入具有相同名称的类不是一个好主意。我通过删除dependency_1解决了这个问题。

但是我想知道为什么使用mvn clean package后会有所不同?还是可能有其他问题我没有注意到导致此行为?

2 个答案:

答案 0 :(得分:2)

在Maven中,安装只是将package阶段生成的工件放入本地.m2存储库的另一个阶段。

责怪行者

因此,首先,我将验证mvn clean installmvn clean package在目标目录中产生相同的工件。

对于99%的项目,它们应该相同,尽管从技术上讲,可以编写一个Maven插件,该插件将应用于安装阶段或打包与安装之间的任何阶段。在默认的Maven生命周期中,之间有some phases

您可以添加将在任何阶段应用的插件,因此首先请检查您是否没有

  • 集成前测试
  • 集成测试
  • 集成后测试
  • 验证

同样,如果您怀疑Maven,则只需运行mvn clean package,转到'target'目录,将工件复制到一边,然后运行mvn clean install,然后比较目标。

如果您的组织中有禁止运行mvn install的策略(尽管这是一个很奇怪的决定,因为安装不会影响任何远程操作并且可以在您的计算机上本地运行),那么您始终可以覆盖Maven的默认存储库位置是这样的:

mvn clean install -Dmaven.repo.local=/alternate/repo/location

现在,这是Maven的一部分,如果您看到工件相同,那么就没有理由怪Maven了:)然后检查您的容器

为容器加盖

这使事情变得非常复杂,因为通常容器(例如,我假设您拥有的容器例如tomcat或wildfly)具有层次结构的类加载器。不用说,名称为FQDN但由不同的类加载器加载的类是完全不同的类。

因此,如果在不同的jar中有2个具有相同FQDN的类,并且两个jar都在WAR中(在类路径中),则类加载器将选择出现在类路径中的第一个并进行加载。

在Java中(例如,与C ++不同),这些类是在首次尝试加载类时动态地(按需)加载的,而在程序启动期间不是必需的。

为此添加一个类加载器层次结构(所有“公共”类的父类加载器,以及每个工件的类加载器),该策略可更改可在该级别配置的搜索顺序(父先加载与子先加载)一个容器,您将得到一个相当复杂的策略,如果您想了解那里发生了什么,就必须在调试中解决这个问题。

当然,我的建议是显而易见的-只是不要在同一个程序包中维护这两个类-选择不同的类(不同的包,不同的类名),也许与不同的实现接口,有很多选择。

但是我的直觉告诉您您已经知道这一点,因此几乎不能将其作为答案。 :)

答案 1 :(得分:1)

在我看来,这听起来像是类加载器问题,您确定结果在许多测试中都可以重复吗?

如果在类路径上有2个具有相同标识符的类,则依赖项的加载顺序将变得很重要,随后的类将覆盖较早的类。此问题通常表现为“不一致的行为”,尤其是在您自己未定义顺序(通过-classpath)并且从目录(例如,WEB-INF/lib)加载依赖项的情况下,然后,任何IO库都会读取文件。

您是正确的删除了重复的依赖关系,这是灾难的根源!