父 pom 和微服务

Parent pom and microservices

让父 pom 将每个微服务声明为模块是个好主意吗?因此有助于管理公共依赖项(例如每个项目都使用 lib servlet-api ,将其全部删除并仅在父 pom 中声明)

带有 multi-module parent pom 的 'problem' 没有复杂的配置文件,它将模块锁定在同一发布周期(假设您使用的是 Release Plugin,你应该是)。

我使用 Maven 的方式是有一个 parent pom 声明:

每个模块都将 parent pom 作为它的 parent,但是 parent 对模块一无所知。

这样做的好处来自上面的最后两个项目符号,即 'management' 部分。 'management' 部分中包含的任何内容都需要在想要使用特定依赖项或插件的模块中重新声明。

例如 parent 可能如下所示:

<project>

  <groupId>com.example</groupId>
  <artifactId>parent</artifactId>
  <version>1.0.00-SNAPSHOT</version>

  ...

  <dependencies>

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.7</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>            

  </dependencies>

  <dependencyManagement>

    <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>
      <version>2.6</version>
    </dependency>        

    <dependency>
      <groupId>commons-collections</groupId>
      <artifactId>commons-collections</artifactId>
      <version>2.1</version>
    </dependency>

  </dependencyManagement>

  <plugins>

    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.1</version>
      <configuration>
        <source>1.8</source>
        <target>1.8</target>
      </configuration>
    </plugin>

  <plugins>

  <pluginManagement>

    <plugins>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.4</version>
        <configuration>
          <appendAssemblyId>false</appendAssemblyId>
          <descriptors>
            <descriptor>src/main/assembly/assembly.xml</descriptor>
          </descriptors>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

    </plugins>

  </pluginManagement>

</project>

模块可能如下所示:

<project>

  <parent>
    <groupId>com.example</groupId>
    <artifactId>parent</artifactId>
    <version>1.0.00-SNAPSHOT</version>
  </parent>

  <groupId>com.example</groupId>
  <artifactId>module</artifactId>
  <version>1.0.00-SNAPSHOT</version>

  <dependencies>

    <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>          
    </dependency>        

  </dependencies>

  <plugins>

    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-assembly-plugin</artifactId>
    </plugin>

  </plugins>

</project>

该模块将:

  • 依赖于 org.slf4j:slf4j-api:1.7.7:compilejunit:junit:4.11:testcommons-lang:commons-lang:2.6:compile
  • 有插件org.apache.maven.plugins:maven-assembly-plugin:2.4

我会避免 parent pom 中的依赖项。如果您的(独立)微服务之一想要其他东西,那就很尴尬了。让 parent 知道每个微服务是很奇怪的。

如果需要,您可以坚持使用 dependencyManagement 以建议默认 versions/scopes。 parent pom 非常方便定义插件、存储库等。

相反,我会将一组通用的依赖项分组到一个特定的工件中,它可能只是一个具有依赖项的 pom。然后你可以依赖,比如 "com.example/common-db-dependencies/1.2" 来包含一组标准的数据库依赖项,比如 hibernate、apache derby 和 JPA 规范。 (或者你正在使用的任何东西)。不使用 JPA/SQL 的服务可以一起避免这种依赖性。

还是别纠结了。如果您试图涵盖每种情况,很容易过度使用依赖结构。因此,只尝试标准化真正被大多数服务使用的东西。

此处存在一个与依赖关系和依赖关系管理有关的问题。假设您的一个微服务出于某种原因想要升级到较新版本的 common ……您不能这样做,因为您有 parent。我确实理解减少插件配置等冗余事物重复的诱惑。在微服务中我们需要更多的考虑各个服务的独立性。

有些配置很常见,例如您的存储库或发布配置等。

我肯定会使用 父项目

多年来我一直在研究这两种结构...微服务与否,模块化与否,Ant、Maven 和 Gradle..

我们需要明白,使用父pom并不意味着谈论微服务不耦合和独立:

  • 它们仍然可以独立,而不是使用父 pom 耦合,
  • 即使您使用的是父 pom,它们仍然可以独立构建和更新。

我听说"a microservice may need to use different versions for a dependency",你可以,只需覆盖特定微服务 pom 中的依赖项即可。

我们需要关注 "What are here the benefit and what are the cons":

  • 控制和标准化:我可以在一个点上管理公共依赖项(使用依赖项管理),它更容易在所有模块中推出依赖项更改,是的我们可能需要不同的第三方版本,但同时我们需要避免失去对所有依赖项的控制,因此可能允许例外,但需要与 "standardization"
  • 保持平衡
  • 组管理:我仍然可以只发布一个模块,但我也可以更轻松地管理多个模块的发布,而不必逐个模块发布,而只是正在开发的模块,在这种情况下,我仍然有一个入口点,所有常见的依赖项都可以是父
  • 的概述

还有更多:

  • 常见的第三方和平台依赖管理
  • 通用第三方和平台标准化
  • 完全控制整个应用程序的依赖生态系统(微服务结构)
  • 常用插件管理和标准化
  • 减少重复和冗余逻辑。
  • 配置管理和标准化
  • 更容易维护,更改一处而不是可能的 30 处!!
  • 更容易测试和推出常见的更改。

缺点呢? 我目前没有看到任何异常,因为可以通过覆盖特定微服务 pom 中的常见行为来管理异常,我仍然可以隔离地管理任何东西(隔离构建、隔离发布、隔离部署……) 没有耦合

还不确定我们所说的“它在同一个发布周期中锁定模块”是什么意思它不会,除非你使用外部快照,我可以在隔离重新使用相同的父版本。

例如,我可以让模块 1 声明 Parent 1.0 并单独发布,而不必 运行 来自父模块的发布过程,我可以 运行 直接在子模块上,但是我不需要在子模块项目中声明任何外部 SNAPSHOT(无论是否有父级,你都会遇到同样的问题)

大多数关于微服务架构的书籍都推荐以自治为原则。使用 parent pom 违反了该原则。

首先使用 parent pom 你不能 不再采用多语言方法并使用不同语言编写您的微服务。

您还将被迫使用 parent 规定的依赖项,尤其是在使用 enforcer 插件的情况下。

微服务将不再可独立部署。

如果您在任何一个微服务上的工作涉及更改 parent。

,那么您在任何一个微服务上的工作也可能会破坏其他微服务。

对微服务使用父 pom 方法的一个主要缺点是它会使微服务的发布管理变得有点棘手。一些相关的指针-

  • 父 pom 不应经常更改,应作为单独的项目在单独的 repo 中进行管理。
  • 对父 pom 的每次更改都应增加父 pom 版本。更改完成后,还应标记父 pom 存储库。 (将其视为具有独立版本的单独库)
  • 此外,所有被触及的微服务的子pom最好更新为指向最新的父pom版本(一定程度上影响微服务的自主性)。这也可能导致强制要求升级微服务以使用更新版本的库,这可能并不总是一个可行的选择。
  • 即使微服务中的唯一变化是指向新的父 pom 版本,它也会调用服务的新版本(主要是次要版本)。

建议 -

  • 您可以使用 maven enforcer 插件检查父子 pom 之间指定的重复依赖版本。
  • 父 pom 对于广泛的依赖关系和依赖关系管理不是一个好的选择,但肯定可以用于存储库、分发管理和插件管理等通常不会在微服务之间发生冲突的事情。