Maven插件前缀解析如何工作? 为什么它解决“findbugs”而不是“jetty”?

我正在使用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文件中:

  org.eclipse.jetty jetty-maven-plugin 9.2.11.v20150529  

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

您刚刚遇到了Maven的插件前缀解析 。 这是一个使用户能够通过使用其前缀来调用特定Maven插件的目标的function。 在命令行上直接调用目标时,可以使用function齐全的forms:

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

这将调用具有坐标my.plugin.groupId:foo-maven-plugin:1.0.0 (以groupId:artifactId:version的forms)的Foo Maven插件的目标bar 。 它运作良好,但有点冗长。 如果不指定所有这些坐标,以更简单的方式调用此目标会很好。 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文件中,您可以添加以下forms的插件组 :

  org.mortbay.jetty  

这样做,告诉Maven当你在命令中使用前缀时应该考虑哪个组ID。 默认情况下,除了设置中指定的组之外, Maven还会搜索组ids org.apache.maven.pluginsorg.codehaus.mojo 。 它会在您在设置中配置的默认值之后搜索这些默认值。 因此,通过上面的配置和mvn foo:bar的命令,Maven将在组id org.mortbay.jettyorg.apache.maven.pluginsorg.codehaus.mojo查找前缀为foo的插件。 。

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

    Some Awesome Maven Plugin somePrefix some-maven-plugin    

如果部分中没有一个

等于我们指定的那个( foo ),Maven将继续使用下一个组ID,点击http://repo1.maven.org/maven2/org/codehaus/mojo/maven-metadata.xml 。 再次,如果没有找到,Maven将最终点击http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-metadata.xml (注意Downloading:登录你的mvn jetty:run命令,完全取出最后两个文件)。 如果仍然没有找到,Maven就不能再为你做什么,而且会出错:

[错误]在当前项目和插件组[org.mortbay.jetty,org.apache.maven.plugins,org.codehaus.mojo]中找不到前缀’foo’的插件,可从存储库[local(.. ./.m2/repository),central(http://repo.maven.apache.org/maven2) ] – > [帮助1]

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

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

将使用哪个版本?

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

  org.apache.maven.plugins maven-clean-plugin  3.0.0 3.0.0  2.0-beta-1 2.0-rc1 2.0 2.1  3.0.0  20151022205339   

Maven 将选择 版本作为版本 ,该版本代表插件的最新版本。 如果那个标签不存在,它将选择 ,它代表插件,发行版或快照的最新版本。 可能会发生两个标签都不存在,在这种情况下,Maven 将选择 元素列表的第一个版本或缺少版本的第一个快照 。

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

我的配置有什么问题?

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

 mvn findbugs:findbugs 

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

它确实找到了一个: Findbugs Maven插件是在org.codehaus.mojo组id下发布的; 实际上,你可以在maven-metadata.xml找到它:

  FindBugs Maven Plugin findbugs findbugs-maven-plugin  

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

第二个例子是命令

 mvn jetty:run 

和以前一样,会发生相同的解决步骤,但是,在这种情况下,您会发现前缀没有出现在组ids org.codehaus.mojoorg.apache.maven.plugins任何maven-metadata.xmlorg.apache.maven.plugins 。 因此解决方案失败,Maven返回您所拥有的错误。

但我们已经看到了如何让它发挥作用! 我们可以在设置中添加 ,以便在解析期间也可以搜索此组ID。 Jetty Maven插件是在组ID org.eclipse.jetty下发布的,如果我们查看Maven Central中相应的maven-metadata.xml ,你会看到

jetty就在那里。 因此修复很简单:只需定义此新组ID即可在设置中进行搜索:

  org.eclipse.jetty  

现在,Maven还将查看此组ID,并将jetty前缀与org.eclipse.jetty:jetty-maven-plugin成功匹配。

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

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

  org.eclipse.jetty jetty-maven-plugin 9.2.11.v20150529  

并使用

 mvn jetty:run 

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

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