Как работает разрешение префикса плагина Maven? Почему он разрешает «findbugs», но не «jetty»?

#java #maven #maven-metadata

#java #maven #maven-метаданные

Вопрос:

Я проводил некоторое тестирование с использованием Maven и понял, что могу выполнить findbugs цель плагина Findbugs без добавления плагина в POM-файл. С другой стороны, когда мне нужно было выполнить run цель плагина Jetty, я был вынужден добавить плагин в файл POM или сборка завершилась неудачно.

  • Почему Jetty требовалась настройка в POM, а Findbugs — нет?
  • Как Maven узнает, какие Findbugs выполнять (предположим, у нас есть плагины с тем же именем, но с другим идентификатором группы)?

Когда я запускаю первую команду, сборка выполняется успешно без каких-либо изменений в файле 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:

Что такое префикс и зачем он нам нужен?

Вы только что столкнулись с разрешением префикса плагина Maven. Это функция, которая позволяет пользователю вызывать цели конкретного плагина 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. Это соответствует простому имени, используемому для его идентификации:

Обычные форматы идентификаторов артефактов для использования являются:

  • maven-${prefix}-plugin — для официальных плагинов, поддерживаемых самой командой Apache Maven (вы не должны использовать этот шаблон именования для своего плагина, смотрите Эту заметку для получения дополнительной информации)
  • ${prefix}-maven-plugin — для плагинов из других источников

Если artifactId вашего плагина соответствует этому шаблону, Maven автоматически сопоставит ваш плагин с правильным префиксом в метаданных, хранящихся в пути groupId вашего плагина в репозитории.

Другими словами, если идентификатор артефакта вашего плагина назван foo-maven-plugin , Maven автоматически присвоит ему префикс foo . Если вам не нужно это назначение по умолчанию, вы все равно можете настроить свое собственное с помощью maven-plugin-plugin и его goalPrefix параметра.

Как Maven сопоставляет префиксы плагинам?

В команде

 mvn foo:bar
  

У Maven должен быть способ определить, что foo на самом деле означает my.plugin.groupId:foo-maven-plugin . В settings.xml файле вы можете добавить группы плагинов в виде:

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

Что это делает, так это сообщает Maven, какой идентификатор группы он должен учитывать, когда вы используете префикс в команде. По умолчанию, и в дополнение к группам, указанным в настройках, Maven также выполняет поиск по идентификаторам групп org.apache.maven.plugins и org.codehaus.mojo . Он выполняет поиск по умолчанию после тех, которые вы настроили в настройках. Следовательно, с описанной выше конфигурацией и командой mvn foo:bar Maven будет искать плагин, имеющий префикс foo внутри идентификатора группы org.mortbay.jetty , org.apache.maven.plugins и org.codehaus.mojo .

Второй шаг заключается в том, как на самом деле выполняется этот поиск. Maven загрузит файлы метаданных (или просмотрит их в вашем локальном репозитории, если они уже загружены), вызываемые maven-metadata.xml , из каждого удаленного репозитория с этими идентификаторами групп. Если мы возьмем пример, где единственным удаленным репозиторием, который у нас есть, является Maven Central, Maven сначала загрузит http://repo1.maven.org/maven2/org/mortbay/jetty/maven-metadata.xml и посмотрит внутри этого файла, есть ли у нас что-то сопоставляющее foo . Обратите внимание, как идентификатор группы был преобразован в структуру каталогов в удаленном репозитории. Структура этого файла метаданных такова:

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

Если ни один из <plugin> разделов не содержит a <prefix> , равного указанному нами ( foo ), Maven продолжит работу со следующим идентификатором группы, нажав 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 больше ничего не может для вас сделать, и это приведет к ошибке:

[ОШИБКА] Плагин не найден для префикса ‘foo’ в текущем проекте и в группах плагинов [org.mortbay.jetty, org.apache.maven.plugins, org.codehaus.mojo] доступны из репозиториев [local (…/.m2 / repository), central (http://repo.maven.apache.org/maven2 )] -> [Справка 1]

Это ошибка, с которой вы столкнулись здесь. Однако, если во время этого поиска было найдено одно совпадение, то Maven может вывести <artifactId> для использования.

Теперь это означает, что у него есть идентификатор группы и идентификатор артефакта. Последняя часть головоломки — это версия

Какая версия будет использоваться?

Maven выберет последний доступный, если он явно не настроен в POM (см. Следующий раздел). Все возможные версии извлекаются путем извлечения другого файла метаданных, который по-прежнему называется maven-metadata.xml , но на этот раз находится рядом с папкой artifact id в репозитории (в отличие от приведенных выше, где он был рядом с идентификатором группы). На примере плагина Maven Clean (идентификатор группы которого и идентификатор артефакта были бы найдены с помощью вышеупомянутого механизма и команды 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 выберет в качестве версии <release> версию, которая представляет последнюю версию плагина. Если этого тега там нет, он выберет <latest> , которые представляют последнюю версию плагина, релиз или снимок. Может случиться так, что оба тега отсутствуют, и в этом случае Maven выберет первый выпуск или первый снимок из-за отсутствия выпуска из списка <version> элементов.

Если это по-прежнему не удается, Maven больше ничего не может для вас сделать, версия не может быть выведена и выдает ошибки. Хотя это маловероятно. Теперь мы собрали идентификатор группы, идентификатор артефакта и версию; время, наконец, вызвать bar цель нашего плагина.

В чем проблема с моей конфигурацией?

Как сказано выше, Maven просматривает определенные предопределенные идентификаторы групп внутри активных удаленных репозиториев для поиска совпадений с заданным префиксом. С помощью команды

 mvn findbugs:findbugs
  

Maven начинает поиск с findbugs префикса. Поскольку в нашей конфигурации их нет <pluginGroup> в наших настройках, Maven проверяет org.codehaus.mojo и org.apache.maven.plugins идентификатор группы на соответствие префикса.

И он находит один: плагин Findbugs Maven опубликован под org.codehaus.mojo идентификатором группы; действительно, вы можете найти его в maven-metadata.xml :

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

И вы также можете найти версию, которая будет использоваться, заглянув в maven-metadata.xml файл под findbugs-maven-plugin только что выведенным (3.0.4 на момент написания этой статьи; и обратите внимание, насколько она точно соответствует версии в mvn findbugs:findbugs журналах вашего вопроса). Итак, разрешение выполнено успешно, и затем Maven может продолжить вызывать findbugs цель этого плагина.

Второй пример — команда

 mvn jetty:run
  

Как и раньше, выполняются те же шаги разрешения, но в этом случае вы обнаружите, что префикс <jetty> не отображается ни в одном из maven-metadata.xml для идентификаторов групп org.codehaus.mojo и org.apache.maven.plugins . Итак, разрешение не выполняется, и Maven возвращает ошибку, которая у вас есть.

Но мы видели, как заставить это работать! Мы можем добавить <pluginGroup> в наши настройки, чтобы этот идентификатор группы также можно было искать во время разрешения. Плагин Jetty Maven опубликован под идентификатором группы org.eclipse.jetty , и если мы заглянем в соответствующий maven-metadata.xml раздел в Maven Central, вы увидите, что <prefix>jetty</prefix> он там есть. Итак, исправление простое: просто определите этот новый идентификатор группы для поиска в настройках:

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

Теперь Maven также проверит этот идентификатор группы и успешно сопоставит jetty префикс с org.eclipse.jetty:jetty-maven-plugin .

Как я могу использовать определенную версию? Или я не хочу изменять свои настройки!

Конечно, все это разрешение можно обойти стороной, если вы явно определяете плагин в своем POM, что является другим решением, которое вы нашли:

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

и используйте

 mvn jetty:run
  

Если вы настроите плагин непосредственно в POM, разрешение префикса все равно произойдет, но оно немного замаскировано: Maven загрузит плагин из настроенных удаленных репозиториев и по пути загрузит и установит все файлы метаданных, включая maven-metadata.xml содержащий сопоставление для префикса jetty . Итак, поскольку он загружает его автоматически, поиск всегда выполняется успешно.

Обратите также внимание, что, поскольку плагин был определен в POM, вам не понадобились бы никакие <pluginGroup> настройки: идентификатор группы был записан в POM. Кроме того, он гарантирует, что будет использоваться версия 9.2.11.v20150529, а не последняя.

Комментарии:

1. Это было исчерпывающее объяснение, именно то, что я искал. Спасибо.