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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40205664/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 22:31:05  来源:igfitidea点击:

How does Maven plugin prefix resolution work? Why is it resolving "findbugs" but not "jetty"?

javamavenmaven-metadata

提问by Jachk E

I was doing some testing using Maven and realized that I can execute the findbugsgoal of the Findbugs plugin without adding the plugin to the POM file. On the other hand, when I needed to run the rungoal of the Jetty plugin, I was forced to add the plugin to the POM file or the build failed.

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

  • Why Jetty needed configuration in the POM while Findbugs didn't?
  • How does Maven know which Findbugs to execute (suppose we have to plugins with the same name but different group id)?
  • 为什么 Jetty 需要在 POM 中进行配置而 Findbugs 不需要?
  • Maven 如何知道要执行哪些 Findbug(假设我们必须使用相同名称但不同组 ID 的插件)?

When I run the first command the build is successful without any changes in POM file:

当我运行第一个命令时,构建成功,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] -----------------------------------------------------------------------

But when I run the second I get this:

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

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

So in order to pass the build I needed to add the following to the pom file:

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

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

采纳答案by Tunaki

What is a prefix and why do we need it?

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

You just encountered the Plugin Prefix Resolutionof Maven. This is a feature which enables the user to invoke goals of a specific Maven plugin, by using its prefix. When you invoke directly a goal on the command-line, you could use the fully-featured form of:

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

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

This would invoke the goal barof the Foo Maven plugin having the coordinates my.plugin.groupId:foo-maven-plugin:1.0.0(in the form of groupId:artifactId:version). It works well, but it is a bit verbose. It would be nice to invoke this goal in a simpler manner, without specifying all those coordinates. Maven makes this possible by assigning prefixes to plugins, so that you can refer to this prefix instead of the whole coordinates, with:

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

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

How is this prefix determined?

这个前缀是如何确定的?

You can define a prefix for each Maven plugin. This corresponds to a simple name used to identify it:

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

The conventional artifact ID formats to use are:

  • maven-${prefix}-plugin- for official plugins maintained by the Apache Maven team itself (you must not use this naming pattern for your plugin, see this note for more informations)
  • ${prefix}-maven-plugin- for plugins from other sources

If your plugin's artifactId fits this pattern, Maven will automatically map your plugin to the correct prefix in the metadata stored within your plugin's groupId path on the repository.

要使用的常规工件 ID 格式是:

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

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

Put another way, if your plugin's artifact id is named foo-maven-plugin, Maven will automatically assign it a prefix of foo. If you don't want this default assignment, you can still configure your own with the help of the maven-plugin-pluginand its goalPrefixparameter.

换句话说,如果您的插件的工件 id 名为foo-maven-plugin,Maven 将自动为其分配一个前缀foo. 如果您不想要此默认分配,您仍然可以在maven-plugin-plugin及其goalPrefix参数的帮助下配置您自己的分配。

How does Maven map prefixes to plugins?

Maven 如何将前缀映射到插件?

In the command

在命令中

mvn foo:bar

Maven must have a way to deduce that fooactually means my.plugin.groupId:foo-maven-plugin. In the settings.xmlfile, you can add plugin groups, in the form of:

Maven 必须有一种方法来推断这foo实际上意味着my.plugin.groupId:foo-maven-plugin. 在settings.xml文件中,您可以添加插件组,格式为:

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

What this does, is telling Maven which group id it is supposed to consider when you're using a prefix in a command. By default, and in addition to the groups specified in the settings, Maven also searches the group ids org.apache.maven.pluginsand org.codehaus.mojo. It searches those default ones after the ones you configured in the settings. Therefore, with the configuration above, and a command of mvn foo:bar, Maven will look for a plugin having a prefix of fooinside the group id org.mortbay.jetty, org.apache.maven.pluginsand org.codehaus.mojo.

它的作用是告诉 Maven 当您在命令中使用前缀时应该考虑哪个组 ID。默认情况下,除了设置中指定的组外,Maven 还会搜索组 IDorg.apache.maven.pluginsorg.codehaus.mojo. 它会在您在设置中配置的那些默认值之后搜索这些默认值。因此,利用上述结构,和一个命令mvn foo:bar,Maven会寻找具有的前缀插件foo组id内org.mortbay.jettyorg.apache.maven.pluginsorg.codehaus.mojo

The second step is how that search is actually performed. Maven will download metadata files (or look them into your local repository if they are already downloaded), called maven-metadata.xml, from each remote repositories at those group ids. If we take the example where the only remote repository we have is Maven Central, Maven will first download http://repo1.maven.org/maven2/org/mortbay/jetty/maven-metadata.xml, and look inside this file if we have something mapping foo. Notice how the group id was transformed into a directory structure in the remote repository. The structure of this metadata file is:

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

<metadata>
  <plugins>
    <plugin>
      <name>Some Awesome Maven Plugin</name>
      <prefix>somePrefix</prefix>
      <artifactId>some-maven-plugin</artifactId>
    </plugin>
  </plugins>
</metadata>

If none of the <plugin>section contain a <prefix>that is equal to the one we specified (foo), Maven will continue with the next group id, hitting http://repo1.maven.org/maven2/org/codehaus/mojo/maven-metadata.xml. Again, if none are found, Maven will finally hit http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-metadata.xml(notice the Downloading:logs in your mvn jetty:runcommand, exactly fetching those last two files). If none are still found, there is nothing Maven can do for you anymore, and it will error:

如果没有任何<plugin>部分包含<prefix>与我们指定的 ( foo)相等的a ,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 就无能为力了,它会报错:

[ERROR] No plugin found for prefix 'foo' in the current project and in the plugin groups [org.mortbay.jetty, org.apache.maven.plugins, org.codehaus.mojo] available from the repositories [local (.../.m2/repository), central (http://repo.maven.apache.org/maven2)]-> [Help 1]

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

This is the error you have here. However, if one match was made during this search, then Maven can deduce the <artifactId>to use.

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

It now means it has the group id, and the artifact id. The final piece of the puzzle is the version

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

Which version is going to be used?

将使用哪个版本?

Maven will take the latest one available, unless explicitly configured in the POM (see next section). All possible versions are retrieved by fetching another metadata file, still called maven-metadata.xml, but this time living alongside the artifact id folder in the repository (contrary to the ones above, where it was alongside the group id). Taking the example of the Maven Clean plugin (whose group id and artifact id would be found with the above mechanism and a command of mvn clean:clean), the maven-metadata.xmllooks like:

Maven 将采用最新的可用版本,除非在 POM 中明确配置(参见下一节)。所有可能的版本都是通过获取另一个元数据文件来检索的,仍然称为maven-metadata.xml,但这次与存储库中的工件 id 文件夹一起存在(与上面的相反,它与组 id 并排)。以 Maven Clean 插件为例(其组 ID 和工件 ID 将通过上述机制和 的命令找到mvn clean:clean),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 will select as versionthe <release>version, which represents the latest release version of the plugin. If that tag isn't there, it will select <latest>which represent the latest version of the plugin, release or snapshot. It can happen that both tags are not there, in which case, Maven will select the first release, or the first snapshot for lack of a release, of the list of <version>elements.

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

If that still fails, there is nothing Maven can do for you anymore, the version couldn't be deduced and it errors. This isn't very likely to happen though. We now have gathered the group id, the artifact id, and the version; time to finally invoke the bargoal of our plugin.

如果仍然失败,则 Maven 再也无法为您做任何事情,无法推断出版本并且出现错误。不过这不太可能发生。我们现在已经收集了组 ID、工件 ID 和版本;是时候最终调用bar我们插件的目标了。

What's the issue with my configuration?

我的配置有什么问题?

As said above, Maven looks in certain pre-defined group ids inside the active remote repositories to look for matches with a given prefix. With the command

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

mvn findbugs:findbugs

Maven starts the search with the findbugsprefix. Since our configuration does not have any <pluginGroup>in our settings, Maven looks into org.codehaus.mojoand org.apache.maven.pluginsgroup id for a prefix match.

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

And it does find one: Findbugs Maven Pluginis published under the org.codehaus.mojogroup id; indeed, you can find it in the maven-metadata.xml:

它确实找到了一个:Findbugs Maven Plugin发布在org.codehaus.mojogroup id 下;实际上,您可以在以下位置maven-metadata.xml找到它:

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

And you can also find the version that is going to be used by peeking into the maven-metadata.xmlfile under the findbugs-maven-pluginjust deduced (3.0.4 at the time of this writing; and notice how it exactly matches the version in the mvn findbugs:findbugslogs of your question). So the resolution succeeded, and then Maven can continue to invoke the findbugsgoal of this plugin.

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

The second example is the command

第二个例子是命令

mvn jetty:run

As before, the same resolution steps happen, but, in this case, you'll find out that the prefix <jetty>does not appear in any of the maven-metadata.xmlfor the group ids org.codehaus.mojoand org.apache.maven.plugins. So the resolution fails, and Maven returns the error that you have.

和以前一样,发生了相同的解析步骤,但是,在这种情况下,您会发现前缀<jetty>没有出现在maven-metadata.xml组 idorg.codehaus.mojo和 的任何 中org.apache.maven.plugins。因此解析失败,Maven 返回您遇到的错误。

But we've seen how to make it work! We can add a <pluginGroup>inside our settings, so that this group id can also be searched during resolution. The Jetty Maven Pluginis published under the group id org.eclipse.jetty, and if we peek into the corresponding maven-metadata.xmlin Maven Central, you'll see that <prefix>jetty</prefix>is there. So the fix is simple: just define this new group id to search inside the settings:

但我们已经看到了如何让它发挥作用!我们可以<pluginGroup>在我们的设置中添加一个,以便在解析过程中也可以搜索到这个组 ID。该码头Maven插件是组ID下发布org.eclipse.jetty的,如果我们窥视到相应maven-metadata.xml的Maven的中央,你会发现<prefix>jetty</prefix>在那里。所以修复很简单:只需定义这个新的组 ID 即可在设置中进行搜索:

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

Now, Maven will also look into this group id, and match the jettyprefix to the org.eclipse.jetty:jetty-maven-pluginsuccessfully.

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

How can I use a specific version? Or, I don't want to modify my settings!

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

Of course, all of this resolution can be side-tracked if you define the plugin explicitly in your POM, which is the other solution you found:

当然,如果您在 POM 中明确定义插件,则所有这些解决方案都可以被忽略,这是您找到的另一个解决方案:

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

and use

并使用

mvn jetty:run

If you configure the plugin directly in the POM, the prefix resolution still happens, but it is a bit masked: Maven will download the plugin from the configured remote repositories, and will download and install all metadata files along the way, including the maven-metadata.xmlcontaining the mapping for the prefix jetty. So since it downloads it automatically, the search always succeeds.

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

Note also that since the plugin was defined in the POM, you wouldn't need any <pluginGroup>in the settings: the group id was written in the POM. Furthermore, it makes sure that the version 9.2.11.v20150529 is going to be used, instead of the latest.

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