Статьи

Maven Mythbusters — Maven автоматически обновляет каждую сборку

Maven, кажется, является одной из тех тем, которая вызывает страсть у многих разработчиков. По-видимому, некоторые разработчики любят его и считают его очень ценным и экономящим время инструментом, тогда как другие ненавидят его со страстью. (Конечно, есть и другие, которые просто хотят продолжить работу, но те обычно молчат в блогосфере). Время от времени кто-то выходит с записью в блогеобъясняя более или менее подробно, что им так не нравится в Maven. Иногда эти статьи содержат конструктивную критику, которая позволяет Maven развиваться в правильном направлении. Замечательно. Иногда они содержат неточности или недоразумения о том, как работает Maven. Иногда они просто не правы. Но, тем не менее, они представляют восприятие Maven в некоторых частях сообщества Java. Поэтому в этой серии статей я хочу взглянуть на некоторые распространенные мифы и идеи, которые распространяются о Maven, и увидеть, как они выдерживают научную экспертизу.

Миф номер 1: Maven автоматически проверяет и загружает обновления при каждой сборке

Первый миф, который мы рассмотрим, касается сетевых привычек Maven. Действительно, кажется, что распространенная идея о Maven заключается в том, что он замедляет вашу сборку из-за чрезмерного доступа к сети. Вот цитата из недавней записи в блоге, иллюстрирующая и распространяющая эту идею:

«Maven не работает и ошибается, если не думает о том, чтобы замедлять каждую сборку, подключаясь к сети, проверяя каждую зависимость на наличие обновлений и автоматически загружая их»

Интересный. В самом деле, это будет серьезная ошибка! Давайте посмотрим, как эта идея соответствует действительности.

На самом деле, эта идея совершенно ошибочна. Фактически, Maven проверяет обновления SNAPSHOT только один раз в день по умолчанию, и даже это настраивается. В Maven 3 дела идут еще дальше: автоматические обновления по умолчанию отключены — вам придется явно запрашивать обновления (используя опцию -U).

Maven вообще не нужно проверять наличие обновлений плагинов ядра — начиная с Maven 2.0.9 версии плагинов ядра привязаны к используемой вами версии Maven, если вы явно не укажете это иначе. Так что никаких обновлений здесь тоже нет.

Однако, как и снимки, Maven будет проверять обновления плагинов один раз в день, если вы не предоставите версию своего плагина. Поэтому предоставляйте версии для своих плагинов или принимайте затраты на доступ к некоторым сетевым сетям раз в 24 часа. Но рекомендуется практиковать (и на самом деле здравый смысл) указывать номер версии любых плагинов, которые вы используете в своей сборке. Если у вас есть явные номера версий плагинов для плагинов, не относящихся к жизненному циклу, вам также не нужно проверять обновления плагинов.

Так что в теории этот миф должен быть хорошо и действительно разрушен. Однако, согласно традиции MythBuster, мы проверим эту гипотезу с помощью нескольких тестов. Во-первых, давайте попробуем с простым многомодульным проектом. Чтобы было интересно, я удалил несколько каталогов из своего локального репозитория, чтобы сначала Maven загрузил некоторые материалы:

$ mvn clean verify
[INFO] Scanning for projects...
[INFO] Reactor build order: 
[INFO]   Tweeter
[INFO]   Tweeter domain model
[INFO]   Tweeter service layer
[INFO]   Tweeter web application
[INFO] ------------------------------------------------------------------------
[INFO] Building Tweeter
[INFO]    task-segment: [clean, verify]
[INFO] ------------------------------------------------------------------------
[INFO] [clean:clean {execution: default-clean}]
Downloading: <a target="_blank" href="http://localhost:8081/nexus/content/groups/public/org/easyb/easyb/" title="http://localhost:8081/nexus/content/groups/public/org/easyb/easyb/">http://localhost:8081/nexus/content/groups/public/org/easyb/easyb/</a>
0.9.6/easyb-0.9.6.pom
2K downloaded  (easyb-0.9.6.pom)
Downloading: <a target="_blank" href="http://localhost:8081/nexus/content/groups/public/org/easyb/easyb/" title="http://localhost:8081/nexus/content/groups/public/org/easyb/easyb/">http://localhost:8081/nexus/content/groups/public/org/easyb/easyb/</a>
0.9.6/easyb-0.9.6.jar
343K downloaded  (easyb-0.9.6.jar)
[INFO] [easyb:test {execution: default}]
...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] ------------------------------------------------------------------------
[INFO] Tweeter ............................................... SUCCESS [4.434s]
[INFO] Tweeter domain model .................................. SUCCESS [9.724s]
[INFO] Tweeter service layer ................................. SUCCESS [1.722s]
[INFO] Tweeter web application ............................... SUCCESS [30.865s]
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 47 seconds
[INFO] Finished at: Tue Jan 05 12:14:12 NZDT 2010
[INFO] Final Memory: 63M/123M
[INFO] ------------------------------------------------------------------------
2010-01-05 12:14:13.588::INFO:  Shutdown hook executing
2010-01-05 12:14:13.090:/tweeter-web:INFO:  Closing Spring root WebApplicationContext
2010-01-05 12:14:13.092::INFO:  Shutdown hook complete

Это загрузило плагин easyb, потому что у него не было его локально. Справедливо, это то, что он должен делать. Для загрузки он загружает зависимости параллельно, когда это возможно, так что это довольно быстро. Для загрузки Maven необходимо создать приложение, и оно делает это только один раз. Не один раз за проект, а один раз. Но вернемся к обсуждаемой теме: теперь давайте еще раз посмотрим, попытается ли он загрузить какие-либо обновления.

$	mvn clean verify
[INFO] Scanning for projects...
[INFO] Reactor build order: 
[INFO]   Tweeter
[INFO]   Tweeter domain model
[INFO]   Tweeter service layer
[INFO]   Tweeter web application
[INFO] ------------------------------------------------------------------------
[INFO] Building Tweeter
[INFO]    task-segment: [clean, verify]
[INFO] ------------------------------------------------------------------------
[INFO] [clean:clean {execution: default-clean}]
[INFO] Deleting directory /Users/johnsmart/Projects/wakaleo-training/tdd-traini
ng/lab-solutions/tweeter/target
[INFO] [easyb:test {execution: default}]
[INFO] /Users/johnsmart/Projects/wakaleo-training/tdd-training/lab-solutions/tw
eeter/src/test/easyb does not exists.  Skipping easyb testing
[INFO] [site:attach-descriptor {execution: default-attach-descriptor}]
[INFO] ------------------------------------------------------------------------
[INFO] Building Tweeter domain model
[INFO]    task-segment: [clean, verify]
[INFO] ------------------------------------------------------------------------
[INFO] [clean:clean {execution: default-clean}]
[INFO] Deleting directory /Users/johnsmart/Projects/wakaleo-training/tdd-traini
ng/lab-solutions/tweeter/tweeter-core/target
lures: 0, Errors: 0, Skipped: 0
...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] ------------------------------------------------------------------------
[INFO] Tweeter ............................................... SUCCESS [3.266s]
[INFO] Tweeter domain model .................................. SUCCESS [8.338s]
[INFO] Tweeter service layer ................................. SUCCESS [1.830s]
[INFO] Tweeter web application ............................... SUCCESS [20.185s]
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 34 seconds
[INFO] Finished at: Tue Jan 05 12:21:04 NZDT 2010
[INFO] Final Memory: 63M/123M
[INFO] ------------------------------------------------------------------------
2010-01-05 12:21:04.559::INFO:  Shutdown hook executing
2010-01-05 12:21:05.062:/tweeter-web:INFO:  Closing Spring root WebApplicationC
ontext
2010-01-05 12:21:05.064::INFO:  Shutdown hook complete

Нет, там нет загрузок. Это прошло довольно хорошо, но пример мог быть немного простым. Итак, давайте проверим это с реальным проектом среднего размера (около 32000 строк кода) (старый, для загрузки!):

$ mvn verify
[INFO] Scanning for projects...
[INFO] Reactor build order: 
[INFO]   BNBGlobal parent module
[INFO]   BNBGlobal localization utilities
[INFO]   BNB Global Core Application
[INFO]   BNB Global Web Application
[INFO]   BNBGlobal aggregator module
[INFO] ------------------------------------------------------------------------
[INFO] Building BNBGlobal parent module
[INFO]    task-segment: [verify]
[INFO] ------------------------------------------------------------------------
[INFO] [enforcer:enforce {execution: enforce-java}]
[INFO] [site:attach-descriptor {execution: default-attach-descriptor}]
[INFO] Preparing source:jar
[WARNING] Removing: jar from forked lifecycle, to prevent recursive invocation.
[INFO] [enforcer:enforce {execution: enforce-java}]
[INFO] [source:jar {execution: default}]
[INFO] NOT adding sources to attached artifacts for packaging: 'pom'.
[INFO] ------------------------------------------------------------------------
[INFO] Building BNBGlobal localization utilities
[INFO]    task-segment: [verify]
[INFO] ------------------------------------------------------------------------
[INFO] [enforcer:enforce {execution: enforce-java}]
[INFO] [groovy:generateStubs {execution: default}]
[INFO]  No sources found for Java stub generation
[INFO] [resources:resources {execution: default-resources}]
[INFO] [compiler:compile {execution: default-compile}]
[INFO] Nothing to compile - all classes are up to date
[INFO] [groovy:compile {execution: default}]
[INFO]  No sources found to compile
[INFO] [groovy:generateTestStubs {execution: default}]
[INFO]  No sources found for Java stub generation
[INFO] [resources:testResources {execution: default-testResources}]
[INFO] Copying 24 resources
[INFO] [compiler:testCompile {execution: default-testCompile}]
[INFO] Nothing to compile - all classes are up to date
[INFO] [groovy:testCompile {execution: default}]
[INFO]  No sources found to compile
[INFO] [surefire:test {execution: default-test}]
[INFO] Surefire report directory: /Users/johnsmart/Projects/bnbglobal/bnbglobal
-l10n/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
....
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] ------------------------------------------------------------------------
[INFO] BNBGlobal parent module ............................... SUCCESS [3.378s]
[INFO] BNBGlobal localization utilities ...................... SUCCESS [15.495s]
[INFO] BNB Global Core Application ........................... SUCCESS [23.054s]
[INFO] BNB Global Web Application ............................ SUCCESS [26.336s]
[INFO] BNBGlobal aggregator module ........................... SUCCESS [0.112s]
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 minute 9 seconds
[INFO] Finished at: Wed Jan 06 16:22:07 NZDT 2010
[INFO] Final Memory: 92M/179M
[INFO] ------------------------------------------------------------------------

Хм, обновлений тоже не видно. Просто чтобы убедиться, что мой локальный менеджер репозитория не мешает процессу, я также выполнил те же тесты без settings.xml в моем каталоге .m2, с (жди!) Точно таким же результатом! Таким образом, похоже, что это хорошо и действительно работает — Maven не проверяет наличие обновлений, зависимостей SNAPSHOT, плагинов или чего-либо еще для каждой сборки. Самое большее, он проверяет наличие обновлений SNAPSHOT один раз в день. Он проверяет неверсированные плагины один раз в день, а вовсе не проверяет плагины с поддержкой версий (рекомендуется). А в Maven 3 он только проверяет наличие обновлений, если вы явно просите об этом.

В следующий раз мы рассмотрим еще один миф о Maven: Maven требуется подключение к Интернету для удаления каталога.

(Название и некоторые изображения этого блога, конечно, были бесстыдно украдены из великого и очень научного сериала MythBusters .)

С http://weblogs.java.net/blog/johnsmart