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
How does Maven plugin prefix resolution work? Why is it resolving "findbugs" but not "jetty"?
提问by Jachk E
I was doing some testing using Maven and realized that I can execute the findbugs
goal of the Findbugs plugin without adding the plugin to the POM file. On the other hand, when I needed to run the run
goal of the Jetty plugin, I was forced to add the plugin to the POM file or the build failed.
我正在使用 Maven 进行一些测试,并意识到我可以在findbugs
不将插件添加到 POM 文件的情况下执行Findbugs 插件的目标。另一方面,当我需要运行run
Jetty 插件的目标时,我被迫将插件添加到 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 bar
of 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 sourcesIf 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-plugin
and its goalPrefix
parameter.
换句话说,如果您的插件的工件 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 foo
actually means my.plugin.groupId:foo-maven-plugin
. In the settings.xml
file, 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.plugins
and 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 foo
inside the group id org.mortbay.jetty
, org.apache.maven.plugins
and org.codehaus.mojo
.
它的作用是告诉 Maven 当您在命令中使用前缀时应该考虑哪个组 ID。默认情况下,除了设置中指定的组外,Maven 还会搜索组 IDorg.apache.maven.plugins
和org.codehaus.mojo
. 它会在您在设置中配置的那些默认值之后搜索这些默认值。因此,利用上述结构,和一个命令mvn foo:bar
,Maven会寻找具有的前缀插件foo
组id内org.mortbay.jetty
,org.apache.maven.plugins
和org.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:run
command, 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.xml
looks 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 bar
goal 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 findbugs
prefix. Since our configuration does not have any <pluginGroup>
in our settings, Maven looks into org.codehaus.mojo
and org.apache.maven.plugins
group id for a prefix match.
Maven 以findbugs
前缀开始搜索。由于我们的配置<pluginGroup>
在我们的设置中没有任何内容,Maven 会查看org.codehaus.mojo
和org.apache.maven.plugins
分组 id 以查找前缀匹配。
And it does find one: Findbugs Maven Pluginis published under the org.codehaus.mojo
group id; indeed, you can find it in the maven-metadata.xml
:
它确实找到了一个:Findbugs Maven Plugin发布在org.codehaus.mojo
group 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.xml
file under the findbugs-maven-plugin
just deduced (3.0.4 at the time of this writing; and notice how it exactly matches the version in the mvn findbugs:findbugs
logs of your question). So the resolution succeeded, and then Maven can continue to invoke the findbugs
goal 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.xml
for the group ids org.codehaus.mojo
and 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.xml
in 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 jetty
prefix to the org.eclipse.jetty:jetty-maven-plugin
successfully.
现在,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.xml
containing 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 版本,而不是最新版本。