Всем привет!
Сегодня расскажу о нескольких неочевидных особенностях работы Maven.
1) за каждый этап жизненного цикла сборки Maven отвечает какой-то плагин. Один плагин может покрывать несколько этапов. Это не новость. Я надеюсь) Интересно то, что эти плагины не обязательно указывать в pom, вот минимальный рабочий pom, с которым ваш проект скомпилируется - https://maven.apache.org/guides/introduction/introduction-to-the-pom.html#Minimal_POM
Работает принцип convention over configuration.
А вот описание алгоритма определения нужного плагина: https://maven.apache.org/guides/introduction/introduction-to-plugin-prefix-mapping.html
Перескажу его вкратце.
Если вы указали при сборке фазу жизненного цикла, например, maven install, то определяются все необходимые шаги сборки и требуемые плагины как описано вот тут https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
А далее Maven ищет специальные файлы maven-metadata во всех подключенных к проекту репо, сливает их в один и ищет плагин по атрибуту prefix, который равен указаному вот тут как plugin https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#default-lifecycle-bindings-packaging-ejb-ejb3-jar-par-rar-war
Вот пример базового maven-metadata из Maven Central https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-metadata.xml
Как можно заметить, у большинства плагинов, поисковый префикс является частью artefactId. Это соглашение о наименовании, хотя и не обязательное. Т.е. всегда можно сделать свой maven-metadata-local.xml и привязать нужный плагин к нужной фазе там. Но я бы не рекомендовал так делать, т.к. это завязка на конкретный сборщик, которая хранится отдельно от кода вашего проекта. Также при создании плагина можно назвать его как угодно и указать к какой фазе сборки он привязан, может быть полезно, когда одним словом сложно выразить задачу плагина.
Если вы явно указываете цель для сборки, например, compiler:compile, то выполняется только эта цель, Maven пропускает разбор жизненного цикла сборки, сразу переходит к поиску нужного плагина в maven-metadata, в данном случае по префиксу compiler.
Вопрос - а как Maven определяет версию плагина? Есть еще один maven-metadata файлик с версиями у каждого плагина https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-compiler-plugin/maven-metadata.xml
И как раз здесь лежит подводный камень: когда Maven-у понадобится конкретный плагин - он возьмет последнюю версию из тех, что найдет в подключенных к проекту репозиториях. А брать последнюю версию не всегда хорошо - там могут быть баги, или она просто может криво закачаться, если речь про внутренний прокси репозиторий.
Поэтому рекомендую начинать с минимальным POM, а перед выходом на ПРОМ фиксировать все версии плагинов.
Еще может возникнуть вопрос - а нельзя ли этот фокус провернуть с неофициальными плагинами? Ответ - можно, нужно лишь указать в settings.xml где еще искать maven-metadata.xml:
<pluginGroups>
<pluginGroup>org.codehaus.modello</pluginGroup>
</pluginGroups>
Еще момент - всегда можно добавить в pom конфигурацию плагина и там переопределить фазу сборки, на которой он запустится.
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
В примере цель из плагина jacoco-maven-plugin привяза к фазе test.
Выше я описывал, как работает Maven в режиме convention over configuration.
Продолжение следует...
#maven #buildtool #conv_over_conf
Сегодня расскажу о нескольких неочевидных особенностях работы Maven.
1) за каждый этап жизненного цикла сборки Maven отвечает какой-то плагин. Один плагин может покрывать несколько этапов. Это не новость. Я надеюсь) Интересно то, что эти плагины не обязательно указывать в pom, вот минимальный рабочий pom, с которым ваш проект скомпилируется - https://maven.apache.org/guides/introduction/introduction-to-the-pom.html#Minimal_POM
Работает принцип convention over configuration.
А вот описание алгоритма определения нужного плагина: https://maven.apache.org/guides/introduction/introduction-to-plugin-prefix-mapping.html
Перескажу его вкратце.
Если вы указали при сборке фазу жизненного цикла, например, maven install, то определяются все необходимые шаги сборки и требуемые плагины как описано вот тут https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
А далее Maven ищет специальные файлы maven-metadata во всех подключенных к проекту репо, сливает их в один и ищет плагин по атрибуту prefix, который равен указаному вот тут как plugin https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#default-lifecycle-bindings-packaging-ejb-ejb3-jar-par-rar-war
Вот пример базового maven-metadata из Maven Central https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-metadata.xml
Как можно заметить, у большинства плагинов, поисковый префикс является частью artefactId. Это соглашение о наименовании, хотя и не обязательное. Т.е. всегда можно сделать свой maven-metadata-local.xml и привязать нужный плагин к нужной фазе там. Но я бы не рекомендовал так делать, т.к. это завязка на конкретный сборщик, которая хранится отдельно от кода вашего проекта. Также при создании плагина можно назвать его как угодно и указать к какой фазе сборки он привязан, может быть полезно, когда одним словом сложно выразить задачу плагина.
Если вы явно указываете цель для сборки, например, compiler:compile, то выполняется только эта цель, Maven пропускает разбор жизненного цикла сборки, сразу переходит к поиску нужного плагина в maven-metadata, в данном случае по префиксу compiler.
Вопрос - а как Maven определяет версию плагина? Есть еще один maven-metadata файлик с версиями у каждого плагина https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-compiler-plugin/maven-metadata.xml
И как раз здесь лежит подводный камень: когда Maven-у понадобится конкретный плагин - он возьмет последнюю версию из тех, что найдет в подключенных к проекту репозиториях. А брать последнюю версию не всегда хорошо - там могут быть баги, или она просто может криво закачаться, если речь про внутренний прокси репозиторий.
Поэтому рекомендую начинать с минимальным POM, а перед выходом на ПРОМ фиксировать все версии плагинов.
Еще может возникнуть вопрос - а нельзя ли этот фокус провернуть с неофициальными плагинами? Ответ - можно, нужно лишь указать в settings.xml где еще искать maven-metadata.xml:
<pluginGroups>
<pluginGroup>org.codehaus.modello</pluginGroup>
</pluginGroups>
Еще момент - всегда можно добавить в pom конфигурацию плагина и там переопределить фазу сборки, на которой он запустится.
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
В примере цель из плагина jacoco-maven-plugin привяза к фазе test.
Выше я описывал, как работает Maven в режиме convention over configuration.
Продолжение следует...
#maven #buildtool #conv_over_conf
maven.apache.org
Introduction to the POM – Maven
👍2🔥1
Всем привет!
Продолжим про Maven.
2) Несмотря на то, что к каждой фазе жизненного цикла по умолчанию привязана одна цель (goal) из конкретного плагина, на каждую фазу можно повесить сколько угодно целей. Порядок выполнения - как указано в pom.xml. Это еще одна одна причина, почему полезно явно обьявлять плагины в pom.
3) Если у вас в settings.xml указано несколько репозиториев с артифактами, и поиск по всем не дал результата - будет ошибка, но с некорректным текстом. В ней будет сказано, что артифакта нет в первом по списку репозитории
4) Если какие-то из репозиториев в settings.xml требуют аутентификации, данные для аутентификации были указаны и протухли, то вы узнаете об этом только тогда, когда понадобится обновить библиотеку, которая есть только в этом репозитории. Ошибка с аутентификацией будет в логах каждой сборки, но сборку не ломает
5) Может возникнуть вопрос - а зачем Maven каждый раз ходит по удаленным репозиториям, если зависимости не менялись. Это поведение контролируется параметром репозитория updatePolicy в settings.xml:
<repository>
<id>central</id>
<url>https://repo1.maven.org/maven2</url>
<releases>
<updatePolicy>always</updatePolicy>
</releases>
</repository>
Возможные значения: "always", "daily" (default), "interval:XXX" (in minutes) or "never".
Можно установить never, но есть два риска:
а) не будут подтягиваться новые snapshot,
б) не будут подтягиваться новые версии уже закачанных артифактов. А эту информацию индексирует IDEA и использует при AutoComplition
6) Если сохраненные локально зависимости были повреждены, то принудительно их перезагрузить можно через очистку локального репозитория, который находится в папке .m2. Командой mvn dependency:purge-local-repository, подробнее тут https://www.baeldung.com/maven-force-update или просто грохнув нужную папку в .m2
7) согласно уже упоминаемому ранее принципу convention over configuration по умолчанию в список репозиториев неявно включается Maven Central. Подробнее про settings.xml и его опции можно почитать тут https://habr.com/ru/post/339902/
8) список репозиториев можно задать как в pom.xml, так и в settings.xml. Предпочтительнее второй вариант, особенно при разработке библиотек, особенно внутренних. Причина: адрес репозитория может поменяться, а settings.xml проще обновить централизованно. Не говоря уже про библиотеки, которые придется перевыпускать. Конечно, если вы ходили по ссылке из предыдущего пункта - у нас есть возможность переопределить любой репозиторий из pom через зеркала\mirror в settings.xml. Причем при настройке зеркала можно не только указывать явно заменяемый репозиторий, но и использовать операторы * и ! Но это все же костыль)
#maven #buildtool #conv_over_conf
Продолжим про Maven.
2) Несмотря на то, что к каждой фазе жизненного цикла по умолчанию привязана одна цель (goal) из конкретного плагина, на каждую фазу можно повесить сколько угодно целей. Порядок выполнения - как указано в pom.xml. Это еще одна одна причина, почему полезно явно обьявлять плагины в pom.
3) Если у вас в settings.xml указано несколько репозиториев с артифактами, и поиск по всем не дал результата - будет ошибка, но с некорректным текстом. В ней будет сказано, что артифакта нет в первом по списку репозитории
4) Если какие-то из репозиториев в settings.xml требуют аутентификации, данные для аутентификации были указаны и протухли, то вы узнаете об этом только тогда, когда понадобится обновить библиотеку, которая есть только в этом репозитории. Ошибка с аутентификацией будет в логах каждой сборки, но сборку не ломает
5) Может возникнуть вопрос - а зачем Maven каждый раз ходит по удаленным репозиториям, если зависимости не менялись. Это поведение контролируется параметром репозитория updatePolicy в settings.xml:
<repository>
<id>central</id>
<url>https://repo1.maven.org/maven2</url>
<releases>
<updatePolicy>always</updatePolicy>
</releases>
</repository>
Возможные значения: "always", "daily" (default), "interval:XXX" (in minutes) or "never".
Можно установить never, но есть два риска:
а) не будут подтягиваться новые snapshot,
б) не будут подтягиваться новые версии уже закачанных артифактов. А эту информацию индексирует IDEA и использует при AutoComplition
6) Если сохраненные локально зависимости были повреждены, то принудительно их перезагрузить можно через очистку локального репозитория, который находится в папке .m2. Командой mvn dependency:purge-local-repository, подробнее тут https://www.baeldung.com/maven-force-update или просто грохнув нужную папку в .m2
7) согласно уже упоминаемому ранее принципу convention over configuration по умолчанию в список репозиториев неявно включается Maven Central. Подробнее про settings.xml и его опции можно почитать тут https://habr.com/ru/post/339902/
8) список репозиториев можно задать как в pom.xml, так и в settings.xml. Предпочтительнее второй вариант, особенно при разработке библиотек, особенно внутренних. Причина: адрес репозитория может поменяться, а settings.xml проще обновить централизованно. Не говоря уже про библиотеки, которые придется перевыпускать. Конечно, если вы ходили по ссылке из предыдущего пункта - у нас есть возможность переопределить любой репозиторий из pom через зеркала\mirror в settings.xml. Причем при настройке зеркала можно не только указывать явно заменяемый репозиторий, но и использовать операторы * и ! Но это все же костыль)
#maven #buildtool #conv_over_conf
Baeldung
Force Repository Update with Maven | Baeldung
Explore the options and goals of Maven that forcibly updates our local repository.
👍2