如何将多模块项目迁移到Maven

11

我们试图将几个多模块应用程序移植到Maven,并遇到了一些问题。

每个模块在cvs中都是独立存储的。我们为每个应用程序编写了清单文件,列出了该应用程序所需的模块(以及可选的版本)。并非所有模块都采用Maven格式。

因此,“customer_care”应用程序具有以下清单:

 <manifest>
 <module id="MY_api"/>
 <module id="custcare_webapp"/>
 </manifest>

同样,应用程序'core batch'有一个像这样的清单:

 <manifest>
 <module id="MY_api"/>
 <module id="core"/>
 <module id="batch"/><!--NB this is a non-maven module -->
 </manifest>

我已经开始对我们的代码进行"Maven化",因此MY_api项目有一个pom.xml文件来定义依赖关系,其中包括对另一个内部代码模块"central_config"的依赖。我已经指定了版本RELEASE。

问题

这一切都运行良好,直到我需要创建一个冻结的清单。我可以为每个模块指定一个版本:

 <manifest>
 <module id="MY_api" version="0.123.0"/>
 <module id="core" version="0.456.0"/>
 <module id="batch" version="0.789.0"/><!--NB this is a non-maven module -->
 </manifest>

但是这个构建过程无法再现,因为MY_api中'centralconfig'依赖的版本是'Release'。所以,如果有人发布了'centralconfig'的新版本,那么下次我们构建这个冰冻清单时,它就会不同。

那么为什么我们不使用像central-config这样的硬编码依赖版本呢?因为那样的话,每当有人更新centralconfig到新版本时,我们就需要更新可能有10到20个pom文件。所有依赖于central config的东西,以及依赖于它的一切,都需要更新他们的pom.xml并重新发布。这不仅是大量的工作,我也不知道如何程序化地可靠地识别每个声明了对central config依赖的模块。

一个可能的解决方案?

我可以在一个地方定义'centralconfig.version',然后在所有我的模块中引用它吗?如果可以的话,我应该在哪里做这个?我对父pom不太了解,但我觉得它们可能提供了一个解决方案。

更新

似乎使用父pom是正确的方法。但根据这个问题:Maven项目可以有多个父母吗?,一个Maven子项目不能有多个父母。

那么MY_api模块怎么能同时是custcare_webapp和core_batch的子模块呢?

更新

我得出结论,Maven不符合我的要求,我们已经回到使用ant和CVS构建我们12年前编写的自制解决方案。


我在Maven的多模块项目中一直遇到问题。最终,我转向了Gradle。我实际上在SO上有一篇文章([https://dev59.com/ZGMm5IYBdhLWcg3wT9qU#23701271]),它可能会帮助您开始使用该工具进行多模块项目。那里的其他答案也很有帮助。我并不是要吹嘘自己或Gradle,只是希望这可能有所帮助。如果无法使用Gradle,请理解。 - sparc_spread
@sparc_spread,感谢你的提示。我并不反对使用Gradle,但是它有一定的学习曲线,而且我已经花费了很多时间和精力来让Maven正常工作,如果现在放弃它,重新开始使用Gradle,那将会是一种遗憾。我感觉Maven应该有解决方案,只是还没有找到! - mdarwin
没问题 - 大家都同意。希望你很快就能得到一些答案。 - sparc_spread
1
说实话,我并不真正理解问题的描述。从我所了解的情况来看,似乎只需使用适当的Maven多模块设置,确实需要使用父POM进行依赖管理,这就足够了。但我想我可能只是没有抓住重点。 - Gimby
(提示)将非Maven库安装在单独的文件夹中:>groupId>thirdparty.batch</groupId>。然后,存储库文件夹“thirdparty”可以放置在受控版本控制下。 - Joop Eggen
显示剩余3条评论
2个回答

3

除了使用父结构外,管理版本的更好的另一种选择是导入依赖项。

为了说明这种方式的工作原理,您可以创建一个仅包含POM的项目,用于指定所有模块要使用的版本:

<project>
 <modelVersion>4.0.0</modelVersion>
 <groupId>test</groupId>
 <artifactId>module-versions</artifactId>
 <packaging>pom</packaging>
 <version>1.0</version>
 <dependencyManagement>
   <dependencies>
     <dependency>
       <groupId>test</groupId>
       <artifactId>a</artifactId>
       <version>1.1</version>
     </dependency>
     <dependency>
       <groupId>foo</groupId>
       <artifactId>bar</artifactId>
       <version>2</version>
     </dependency>
   </dependencies>
 </dependencyManagement>
</project>

接下来,在所有需要依赖于你已经硬编码版本的项目中,您可以按照以下方式导入此项目:

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>test</groupId>
        <artifactId>module-versions</artifactId>
        <version>1.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

这样你只需要在发布任何依赖项的新版本时更改module-versions项目。
这样,您可以有多个“module-versions”项目来分割事物。
当然,您仍然面临一个问题,即所有想要使用新版本的项目必须依次发布,但这是在Maven中使用已发布依赖项的成本。

这实际上可能行得通。因此,每个模块,而不是有一个父级或祖先来定义模块版本,将有效地导入“最新模块版本”列表。好的,下一个问题是 - 我应该把这个项目放在哪里?我能确定maven每次都会更新它吗?过去我曾经遇到过maven无法正确从存储库获取版本元数据的问题。 - mdarwin
但是当我增加一个模块的版本号时,我也必须更新这个pom文件。我是否还需要增加这个pom文件的版本号呢?因为如果是这样的话,那么我就必须更新所有依赖于它的其他模块的pom.xml文件,也就是所有的模块... - mdarwin
@mdarwin 是的,你会遇到这种情况,但是在使用发布依赖项时无法避免。您可以使用诸如Maven版本插件之类的工具使其更加容易。 - K Erlandsson

1
我认为你需要一个父POM。这是一个顶级的pom.xml,它仅是一个POM模块,没有相关的代码。通过在这个pom.xml上运行mvn命令来构建整个项目。
POM应该在所有模块目录的上一级目录中。也就是说,每个模块都将位于包含主pom.xml的目录的子目录中。
这个POM的<packaging>类型将是pom。这意味着它是一个仅有自己的POM项目,没有任何代码。它还将具有一个<modules>标记,其中包含每个模块的一个<module>元素。这样,当您运行mvn命令时,Maven将知道构建每个模块。一个不错的示例父POM在这里
使用标准的<dependencies>标签在此POM中设置所有依赖项,模块POM将继承它们。(更新:请参见下面的评论,父POM最好使用<dependencyManagement>标签进行探索。)
最后,每个模块的POM应该引用主POM。这样,如果您在一个模块目录中运行mvn(即仅构建一个模块),它将查找父级的依赖项。您可以使用<parent>标签来实现这一点,它将保存主POM的<groupid><artifactid>。一个很好的<parent>标签示例以及多模块项目的总体审查,在这里

1
准确来说,需要一个“父”pom来保存<dependencyManagent>...依赖项。在模块pom中,<dependency>中不应出现任何<version>。Maven依赖插件可能会提供一些工具,例如这个 - Joop Eggen
1
好观点。我在父POM中没有使用<dependencyManagement>也能运行,但它确实有一些优势。这里有一个很好的解释关于<dependencyManagement>的内容。 - sparc_spread
将 MY_api 制作成一个独立项目。在开发者电脑上,运行 mvn install 命令将会把 MY_api 安装到本地仓库中,因此同一台电脑上的其它项目也能找到它。如果你希望一个项目只使用已发布的 MY_api,则需要使用中央仓库。最常用的中央仓库是 Artifactory。有关仓库管理器的概述,请参阅这里。仓库管理器的比较请见这里 - sparc_spread
我想我明白你的意思 - 也就是说,MY_api希望使用与使用MY_api的其他独立应用程序相同的集中依赖列表。在这种情况下,我会将父POM作为完全版本化的独立项目放入存储库(称其为“POM-central”)。然后,每个多模块本身都有一个父POM,其父级为POM-central。 - sparc_spread
MY_api有2个逻辑父级-customer_care和core_batch。我应该使用哪一个作为父POM,为什么? - mdarwin
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接