插件验证在Maven中如何工作,为什么它用无效版本构建我的项目?

u12*_*123 3 maven

我有一个Maven项目,即使我在POM中指定了一个完全无效的插件,也可以正常运行:

<build>
  <plugins>
    <plugin>
      <groupId>bla</groupId>
      <artifactId>bar</artifactId>
      <version>1.9.553342342343</version>
      <executions>
        <execution>
          <phase>compile</phase>
        </execution>
      </executions>
      <configuration>
        <project>
          <inceptionYear>123123</inceptionYear>
          <contributors>
            asdad
          </contributors>
        </project>
      </configuration>
    </plugin>
  </plugins>
</build>
Run Code Online (Sandbox Code Playgroud)

我也没有在Eclipse中看到任何错误,即使删除了~.m2\repository文件夹,它仍然可以正常运行。Maven验证插件的方式是否有所改变?还是当我宣布目标被炸毁时首先出现?

Tun*_*aki 6

您的问题提出了不同的问题,即由Maven执行的验证检查的种类以及实际执行的时间。坐好,有很多话要说。

步骤1:模型验证

在构建项目模型时,就在构建开始时就完成了第一组验证。该过程由Model Builder组件完成,其目标是将POM文件解析为一个Model对象(以便以后MavenProject可以从其中创建完整的对象,从而显着执行依赖关系调解)。该验证步骤实际上分为两部分:

  • 一个原始模型验证,这是应用在POM原因,任何继承或任何事情之前。它寻找缺少的必需值,例如a groupId,an artifactId或a 的存在version;仓库有一个ID;或者,在您的情况下,该插件具有groupIdartifactId。它实际上不检查是否有版本,因为该版本可以被继承,但尚未完成。
  • 一个有效的模型验证,这是后继承,内插和简档/默认注射进行。此时,该模型应该完全有效。值得注意的是,它必须具有一个packaging,每个依赖项必须具有一个版本,每个插件也必须具有一个版本,依此类推。并且从1.9.553342342343技术上讲,您所拥有的插件版本实际上是完全有效的,这在技​​术上是可接受的版本号。实际上,几乎所有的String都可以作为有效的版本号。非法字符是 \\/:\"<>|?*。另外,<configuration>一个插件的不能得到验证,这仅仅是因为它不能:特定于每个插件,并且可能会声明一个<project>参数。出于同样的原因,它不会检查插件是否真正存在于远程存储库中,或者是否指定了任何目标,阶段等。

因此,在此步骤的最后,该POM已完全验证并且完全可以。

步骤2:建立专案

接下来是从中实际构建MavenProject的步骤。因为Maven需要对项目的依赖项执行依赖关系中介,所以它首先必须下载它们。因此,如果您有任何无效的依存关系(即无法通过设置或项目本身中配置的远程存储库解决的依存关系),将在此处停止。

但是,如果我们设想正确地解决了依赖性,则构建将继续逐个调用每个插件。重要的一点是,只有在Maven检测到将在构建期间调用它们时,才解析插件及其各自的依赖项。如果没有,Maven将不会尝试下载任何内容。此外,在实际调用插件并将值注入到插件中以供其使用时,也会完成插件配置的验证。

根据启动的Maven命令,并非POM中声明的所有插件都可以工作。例如,如果用户输入了阶段,例如mvn clean package则将package调用绑定到干净生命周期阶段或默认生命周期up之前的每个插件;因此绑定到该install阶段的任何插件都不会被调用。同样,如果用户输入了一个目标(例如),mvn org.apache.maven.plugins:maven-clean-plugin:3.0.0:clean则只会调用该特定插件的特定目标,而所有其他插件都将被忽略。

这最后一部分是为什么问题中的POM绝对不会给Maven带来麻烦,并且这里有很多要点:

  1. 它已绑定到compile阶段,但没有<goal>,因此即使要执行该阶段,插件也无能为力,因为未定义目标。Maven知道这一点,并且不会尝试解决插件工件。
  2. 让我们通过添加到插件声明中来设置<goal>to foo并重新测试<goals><goal>foo</goal></goals>。我们在POM中:

    <executions>
      <execution>
        <phase>compile</phase>
        <goals><goal>foo</goal></goals>
      </execution>
    </executions>
    
    Run Code Online (Sandbox Code Playgroud)

    运行mvn clean,或者mvn clean validate仍然绝对不会导致任何问题:该compile阶段未执行。但是现在,如果我们运行mvn compile,我们最终会得到一个错误:

    插件bla:bar:1.9.553342342343或其依赖项之一无法解析

    毕竟,这就是我们想要的。由于插件声明的阶段为compile,并且使用的命令将在该阶段运行,因此Maven尝试下载该插件(但失败)。

  3. 因此,让我们删除该阶段。现在会发生什么?

    <executions>
      <execution>
        <goals><goal>foo</goal></goals>
      </execution>
    </executions>
    
    Run Code Online (Sandbox Code Playgroud)

    实际上,在特定阶段(例如或)运行任何命令现在都会使构建失败。原因是插件可以具有默认阶段(另请参见带注释的目标上的属性)。由于每个插件都可以自行决定是否为其目标提供默认阶段,因此Maven必须下载插件工件,并确定该特定插件是否使用默认插件。因此,我们的构建将再次失败,是的!mvn cleanmvn validatedefaultPhase@Mojo

    如果用户调用特定目标,情况就不同了。尝试mvn clean:clean以上操作,它不会失败。实际上,只会发出警告,指出Maven无法解决插件工件,但这都不是错误,因为调用clean:clean只会调用的特定clean目标maven-clean-plugin。实际上,从理论上讲,这里不应该有任何警告。Maven不应尝试下载任何内容。使用前缀clean要求检查到远程存储库以解决该问题是一个副作用(请参阅此答案以了解其工作原理)。但是,如果您完全有资格使用而不需要任何插件前缀解析mvn org.apache.maven.plugins:maven-clean-plugin:3.0.0:clean,则可以将错误/警告归零。

  4. 最后,如果我们删除所有内容并最终得到

    <executions>
      <execution>
      </execution>
    </executions>
    
    Run Code Online (Sandbox Code Playgroud)

    应该很清楚,您将不执行任何操作都将导致错误,因为绝不能执行该插件。(如果使用前缀,您仍然会收到警告)。

步骤3:插件配置

问题的最后一部分很简单:插件的配置验证。您会注意到这里根本没有提到这一点。这是因为它仅在插件实际执行时发生。而且,由于它甚至不存在,因此不太可能执行。

为了说明起见,我们假设它是。每个插件都配置有特定的配置器。默认情况下,它将XML元素映射到类,字段,列表,映射,数组,就像您期望的那样。您可以提供自己的配置器,但这并不是一件容易的事。实际上,没有执行任何实际的验证:基本上,如果配置器可以在mojo中连接适当的值,那么就完成了。您可以检查默认情况下存在的不同类型的转换器,但是归结为:未指定字符串"foo"到期望的整数值;如果插件期望,则传递正确的枚举名称;为自定义类传递正确的XML配置(即,每个字段都具有自己的XML元素)...值得指出的是,"foo"将值设置为期望的布尔属性不是问题,它将false与值关联。

最后,没有映射到mojo的任何参数的XML配置将被完全忽略,因此,即使bar插件存在并且不带任何参数,<project>在XML配置中传递a 也将被忽略,并且不会导致任何错误。