Maven插件前缀解析如何工作?为什么它会解决" findbugs"但不是"码头"?

时间:2016-10-23 17:18:16

标签: java maven maven-metadata

我正在使用Maven进行一些测试,并意识到我可以执行Findbugs插件的findbugs目标,而无需将插件添加到POM文件中。另一方面,当我需要运行Jetty插件的run目标时,我被迫将插件添加到POM文件或构建失败。

  • 为什么Jetty需要在POM中配置而Findbugs没有?
  • Maven如何知道要执行哪些Findbugs(假设我们必须使用相同名称但不同组ID的插件)?

当我运行第一个命令时,构建成功,而POM文件没有任何更改:

mvn findbugs:findbugs
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building module-mytest 1.0
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- findbugs-maven-plugin:3.0.4:findbugs (default-cli) @ module-mytest ---
[INFO] Fork Value is true
     [java] Warnings generated: 6
[INFO] Done FindBugs Analysis....
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 24.165s
[INFO] Finished at: Sun Oct 23 18:40:26 WEST 2016
[INFO] Final Memory: 21M/111M
[INFO] -----------------------------------------------------------------------

但是当我跑第二个时,我得到了这个:

mvn jetty:run
[INFO] Scanning for projects...
Downloading: http://repo.maven.apache.org/maven2/org/codehaus/mojo/maven-metadata.xml
Downloading: http://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-metadata.xml
Downloaded: http://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-metadata.xml (13 KB at 30.0 KB/sec)
Downloaded: http://repo.maven.apache.org/maven2/org/codehaus/mojo/maven-metadata.xml (20 KB at 41.0 KB/sec)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.129s
[INFO] Finished at: Sun Oct 23 18:43:27 WEST 2016
[INFO] Final Memory: 12M/104M
[INFO] ------------------------------------------------------------------------
[ERROR] No plugin found for prefix 'jetty' in the current project and in the plugin groups [org.apache.maven.plugins, org.codehaus.mojo] available from the repositories [local (/home/hp-pc/.m2/repository), central (http://repo.maven.apache.org/maven2)] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/NoPluginFoundForPrefixException

因此,为了传递构建,我需要将以下内容添加到pom文件中:

<plugin>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-maven-plugin</artifactId>
  <version>9.2.11.v20150529</version>
</plugin>

1 个答案:

答案 0 :(得分:32)

什么是前缀?我们为什么需要它?

您刚刚遇到了Maven的Plugin Prefix Resolution。这是一个允许用户通过使用其前缀来调用特定Maven插件的目标的功能。在命令行上直接调用目标时,可以使用功能齐全的形式:

mvn my.plugin.groupId:foo-maven-plugin:1.0.0:bar

这将调用具有坐标bar的Foo Maven插件的目标my.plugin.groupId:foo-maven-plugin:1.0.0(以groupId:artifactId:version的形式)。它运作良好,但有点冗长。如果不指定所有这些坐标,以更简单的方式调用此目标会很好。 Maven通过为插件分配前缀来实现这一点,因此您可以使用以下内容来引用此前缀而不是整个坐标:

mvn foo:bar
    ^^^ ^^^
     |    |
   prefix |
          |
         goal

如何确定此前缀?

您可以为每个Maven插件定义前缀。这对应于用于标识它的简单名称:

  

要使用的传统工件ID格式为:

     
      
  • maven-${prefix}-plugin - 对于由Apache Maven团队自己维护的官方插件(您不得对插件使用此命名模式,请参阅此说明以获取更多信息)
  •   
  • ${prefix}-maven-plugin - 来自其他来源的插件
  •   
     

如果您的插件的artifactId符合此模式,Maven会自动将您的插件映射到存储库中插件的groupId路径中存储的元数据中的正确前缀。

换句话说,如果您的插件工件ID名为foo-maven-plugin,Maven会自动为其指定foo前缀。如果您不想要此默认分配,您仍然可以借助maven-plugin-plugin及其goalPrefix参数配置自己的分配。

Maven如何映射插件的前缀?

在命令

mvn foo:bar

Maven必须有办法推断出foo实际上意味着my.plugin.groupId:foo-maven-plugin。在settings.xml文件中,您可以添加plugin groups,格式为:

<pluginGroups>
  <pluginGroup>org.mortbay.jetty</pluginGroup>
</pluginGroups>

这样做是告诉Maven当你在命令中使用前缀时应该考虑哪个组ID。默认情况下,除了设置中指定的组Maven also searches the group ids org.apache.maven.plugins and org.codehaus.mojo之外。它会在您在设置中配置的默认值之后搜索这些默认值。因此,通过上面的配置和mvn foo:bar的命令,Maven将在组ID fooorg.mortbay.jetty和{{中找到一个前缀为org.apache.maven.plugins的插件1}}。

第二步是如何实际执行搜索。 Maven将从这些组ID的每个远程存储库下载元数据文件(或者如果它们已经下载,则将其查看到本地存储库中),称为org.codehaus.mojo。如果我们举例说明我们唯一的远程存储库是Maven Central,Maven将首先下载http://repo1.maven.org/maven2/org/mortbay/jetty/maven-metadata.xml,如果我们有映射maven-metadata.xml的内容,请查看此文件。请注意组ID是如何转换为远程存储库中的目录结构的。此元数据文件的结构是:

foo

如果<metadata> <plugins> <plugin> <name>Some Awesome Maven Plugin</name> <prefix>somePrefix</prefix> <artifactId>some-maven-plugin</artifactId> </plugin> </plugins> </metadata> 部分中没有<plugin>包含的内容等于我们指定的<prefix>foo),Maven将继续使用下一个组ID,点击{{3} }。同样,如果没有找到,Maven将最终点击http://repo1.maven.org/maven2/org/codehaus/mojo/maven-metadata.xml(注意Downloading:命令中的mvn jetty:run日志,正好获取最后两个文件)。如果还没有找到,Maven就不能再为你做什么,而且会出错:

  

[错误]找不到前缀&#39; foo&#39;的插件在当前项目和插件组[org.mortbay.jetty,org.apache.maven.plugins,org.codehaus.mojo]中可从存储库[local(... /。m2 / repository),central({ {3}} - &gt; [帮助1]

这是你在这里遇到的错误。但是,如果在此搜索期间进行了一次匹配,则Maven可以推断出要使用的<artifactId>

现在意味着它具有组ID和工件ID。最后一块拼图是版本

将使用哪个版本?

Maven将采用最新的可用,除非在POM中明确配置(参见下一节)。通过获取另一个仍然称为maven-metadata.xml的元数据文件来检索所有可能的版本,但这次与存储库中的工件id文件夹一起生存(与上面的文件夹文件文件夹相反,它与组ID一起)。以Maven Clean插件(其组ID和工件ID将通过上述机制和命令mvn clean:clean找到)为例,http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-metadata.xml看起来像:

<metadata>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-clean-plugin</artifactId>
  <versioning>
    <latest>3.0.0</latest>
    <release>3.0.0</release>
    <versions>
      <version>2.0-beta-1</version>
      <version>2.0-rc1</version>
      <version>2.0</version>
      <version>2.1</version>
      <!-- more versions -->
      <version>3.0.0</version>
    </versions>
    <lastUpdated>20151022205339</lastUpdated>
  </versioning>
</metadata>

Maven http://repo.maven.apache.org/maven2)] <release>版本,代表插件的最新发布版本。如果该标记不存在,则会选择代表插件,发行版或快照的最新版本的<latest>。可能会发生两个标记都不存在,在这种情况下,Maven maven-metadata.xml<version>元素列表。

如果仍然失败,Maven就不能再为你做什么了,版本无法推断出来并且错误。但这不太可能发生。我们现在收集了组ID,工件ID和版本;是时候最终调用插件的bar目标了。

我的配置有什么问题?

如上所述,Maven查看活动远程存储库中的某些预定义组ID以查找具有给定前缀的匹配项。使用命令

mvn findbugs:findbugs

Maven以findbugs前缀开始搜索。由于我们的配置在我们的设置中没有任何<pluginGroup>,因此Maven会查找org.codehaus.mojoorg.apache.maven.plugins组ID以获得前缀匹配。

它找到了一个:will select as versionorg.codehaus.mojo组ID下发布;的确,你可以找到它will select the first release, or the first snapshot for lack of a release

<plugin>
  <name>FindBugs Maven Plugin</name>
  <prefix>findbugs</prefix>
  <artifactId>findbugs-maven-plugin</artifactId>
</plugin>

您还可以通过查看findbugs-maven-plugin刚刚推导出的Findbugs Maven Plugin文件(在撰写本文时为3.0.4)找到将要使用的版本;并注意它是如何使用的与您问题的mvn findbugs:findbugs日志中的版本完全匹配。所以解决方案成功了,然后Maven可以继续调用此插件的in the maven-metadata.xml目标。

第二个例子是命令

mvn jetty:run

与以前一样,会发生相同的解决步骤,但是,在这种情况下,您会发现前缀<jetty>没有出现在任何maven-metadata.xml组ID中{ {1}}和org.codehaus.mojo。所以解决方案失败了,Maven会返回你的错误。

但我们已经看到了如何让它发挥作用!我们可以在设置中添加org.apache.maven.plugins,以便在解析期间也可以搜索此组ID。 maven-metadata.xml已在小组ID <pluginGroup>下发布,如果我们查看相应的findbugs,您会看到org.eclipse.jetty在那里。因此修复很简单:只需定义此新组ID即可在设置中进行搜索:

<prefix>jetty</prefix>

现在,Maven还会查看此组ID,并将<pluginGroups> <pluginGroup>org.eclipse.jetty</pluginGroup> </pluginGroups> 前缀与jetty成功匹配。

我如何使用特定版本?或者,我不想修改我的设置!

当然,如果您在POM中明确定义插件,则可以侧面跟踪所有这些解决方案,这是您找到的另一种解决方案:

org.eclipse.jetty:jetty-maven-plugin

并使用

<plugin>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-maven-plugin</artifactId>
  <version>9.2.11.v20150529</version>
</plugin>

如果您直接在POM中配置插件,前缀解析仍然会发生,但它有点掩盖:Maven将从配置的远程存储库下载插件,并将沿途下载并安装所有元数据文件,包括mvn jetty:run 包含前缀maven-metadata.xml的映射。因此,自动下载后,搜索总会成功。

另请注意,由于插件是在POM中定义的,因此您在设置中不需要任何jetty:组ID是在POM中编写的。此外,它确保将使用版本9.2.11.v20150529,而不是最新版本。