我的项目有两个依赖项,每个依赖项都有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
后会有所不同?还是可能有其他问题我没有注意到导致此行为?
答案 0 :(得分:2)
在Maven中,安装只是将package
阶段生成的工件放入本地.m2存储库的另一个阶段。
责怪行者
因此,首先,我将验证mvn clean install
和mvn 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库都会读取文件。
您是正确的删除了重复的依赖关系,这是灾难的根源!