Comments 64
После того, как maven перестанет качать всякую дрянь из интернета
Ад, конечно.
Не могли бы вы раскрыть свою мысль? :)
Это куда более характерно для ant'а, в котором это очень сильно зависит от того как именно написали build.xml
. mvn -o
и использование внутреннего nexus'а — наше усё.
Тянуть что-либо со стороны — это как раз maven (ну и gradle).
Автору: статья расчитана на новичков, не умеющих делать сборку. Почему вы не началим с простейшего срособа собрать «hello world» без сторонних систем сборок? Или это уже не требуется от желающих найти работу?
Вообще-то Ant по умолчанию вообще ничего на тащит из интернета и не требует его. Если Ant-скрипт что-то и тянет оттуда, то это программист своими очумелыми ручками сделал такой custom-таск (ну, или вставил сторонний таск «для улучшения»).
Я в курсе. Обычно народ пишет таск для выкачивания зависимостей для сборки и далеко не всегда использует нормальные средства (типа ivy
, который, собственно, используется gradle
и sbt
), которые нормально работают с кэшами и имеют offline режим.
Ну да, тут совершенно согласен. Я вообще сначала думал запустить программу через простой вызов бинарника java. Но потом решил, что раз уж в статье акцент на maven, то надо делать им.
Я не помню такого этапа жизненного цикла у maven. Может быть вы имели в виду package?
а чтобы отработал mvn package необходимо указать entity point
а еще лучше mvn deploy
Для того, чтобы объяснить что такое mvn package, нужно объяснить что такое jar и war и, возможно, рассказать про этапы жизненного цикла. По моему, для первого знакомства это слишком много.
Я считаю, что про jar нужно рассказывать в статье про то, как подключить библиотеки, а про стадии жизненного цикла в статье про то, как запустить юнит-тесты.
но тогда зачем рассказывать человеку о maven если можно использовать javac?
и почему именно maven когда я несколько лет сталкивался с java везде повально перезжали на gradle и maven был только там где это исторически сложилось.
Статья ваша вам, видней, по поводу mvn build да был не прав не так написал, имел ввиду именно package.
Видимо надо было подробнее остановиться на вопросе о том, зачем нужен maven, когда есть javac.
maven, помимо того, что о чём написано в статье может делать ещё очень многое. Он может скачать используемые в проекте библиотеки, может разложить куда надо ресурсы может запустить юнит тесты. Кроме того, как верно заметил grossws, он позволяет описать проект и этим описанием может воспользоваться любая современная IDE.
Gradle хорош, но он не стандарт индустрии. Без знания maven пока что обойтись не получится.
про gradle возможно(сколько людей столько и мнений)
и знаю что maven central repository стандарт де факто, который кстате в gradle используется.
Gradle хорош, но он не стандарт индустрии. Без знания maven пока что обойтись не получится.
Не соглашусь с первой частью, но соглашусь со второй.
Насколько я видел по android-проектам, gradle
там является стандартом de facto для сборки.
В мире же java se, когда используют gradle
, sbt
, lein
или ant
для библиотек — всё равно генерируют pom (хотя при использовании ant'а это бывает несколько реже), описывающий проект, но не сборку: всякие вещи типа project/distributionManagement
, project/scm
, project/mailingLists
и т. п. Например, см. фрагмент из sbt'шных скриптов akka.
Вы не смотрели эпик баттл между gradle, maven и svt? Там Барух Садогурский (один из адептов gradle и groovy) говорит, что gradle хорошо, но для кровавого энтерпрайза не готов потому, что слишком гибок.
Хотя про андроид я конечно немного забыл :)
И, в качестве project model для IDE, gradle, боюсь, никогда не потянет в силу той же гибкости и динамичности.
Той же idea приходится исполнять build.gradle на каждый чих при его изменениях, и с десятком зависимостей и без модулей/плагинов это уже становится не менее дорогой операцией, чем изменение зависимостей в maven-проекте с парой-тройкой сотен транзитивных зависимостей и десятком профилей сборки.
Для maven'а существовали (и местами существуют) плагины для генерации проекта под конкретную ide (типа m2e), но использование их, а равно описываемого вами генератора для проекта, имеет один фатальный недостаток: это дополнительное ручное действие, которое надо не забыть сделать после модификации pom.xml
/build.gradle
.
Рано или поздно оно забывается, а дальше — happy-debug. Ловля проблем с неконсистентными версиями зависимостей — очень неприятное развлечение.
maven package
по умолчанию (при packaging=jar
) соберёт jar без зависимостей и запускаться он не будет. Чтобы он запускался надо сделать одно из двух:
- собирать uberjar (с помощью assembly/shade/jarjar/onejar) с указанием
Main-Class
в манифете (можно сделать, например, черезplugin/configuration/archive/addManifestEntries/mainClass
в рамках maven-jar-plugin/maven-shade-plugin или в assembly дескрипторе) - собирать jar+deps (можно использовать к
mainClass
добавитьaddClasspath
плюс опциональноclasspathPrefix
и сложить зависимости в classpath prefix с помощью maven-dependency-plugin'а.
Оно может работать автоматически, если настроено в parent pom'е, но в корневом parent pom'е (который используется по умолчанию) этого нет. Ниже примеры из моего parent'а, которые я использую для сборки uberjar'ов и standalone jar + libs для случаев типа embedded jetty + weld (реализация CDI), которые не работают в режиме uber jar'а либо требуют дополнительной хитрой настройки для работы.
Любой из вариантов ниже (plugin
и ниже по дереву) можно скопировать в project/build/plugins
.
<!-- uberjar -->
<profile>
<id>uberjar-assembly</id>
<activation>
<file>
<exists>.uberjar-assembly</exists>
</file>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<configuration>
<finalName>${project.build.finalName}-uber</finalName>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>${mainClass}</mainClass>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>reference.conf</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformer" />
<transformer implementation="org.apache.maven.plugins.shade.resource.ApacheNoticeResourceTransformer">
<addHeader>false</addHeader>
</transformer>
</transformers>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
Наличие в проекте файла .uberjar-assembly
подключит этот профиль и он будет генерировать jar с classifier'ом uber
, сконфигурированный для запуска через java -jar
. Требует наличие в проекте property mainClass
.
<!-- app assembly -->
<profile>
<id>app-assembly</id>
<activation>
<file>
<exists>.app-assembly</exists>
</file>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>${mainClass}</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
</execution>
</executions>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<stripVersion>false</stripVersion>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>example-assemblies</artifactId>
<version>1</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>app</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
В org.example:example-assemblies:1:jar
должен быть доступен дескриптор такого вида (положить в src/main/resources/assemblies/app.xml
):
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>app</id>
<formats>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<files>
<file>
<!-- fix extra space before `source` tag below -->
< source>target/${project.build.finalName}.jar</source>
<outputDirectory/>
<destName>${project.artifactId}.jar</destName>
</file>
</files>
<dependencySets>
<dependencySet>
<outputDirectory>lib</outputDirectory>
<useProjectArtifact>false</useProjectArtifact>
</dependencySet>
</dependencySets>
</assembly>
Профиль включается наличием файла `.app-assembly` и генерирует `.tar.gz` с приложением и его зависимостями в директории `lib/`.
В случае packaging=war
всё проще, так как war содержит необходимые зависимости в себе и это обеспечивается maven-war-plugin'ом автоматически. Правда, в зависимости от того для servlet container'а оно или для application server'а разный набор зависимостей должен быть со scope=provided
.
Цена на самом деле не велика, правильно настроенный pom.xml
Про это я хочу написать отдельную статью. Благо тема, если её раскрывать полностью, заслуживает чуть ли не книги.
Но на самом деле если сделать как https://git-scm.com/book/ru/v1/, то это будет весьма похвально
Я думаю, стоит. Существующие руководства нередко делают акцент на том, как что-то сделать без объяснения что собственно происходит. Например, мне кажется, что в случае с библиотеками нужно сначала объяснить что такое библиотека, а потом уже коротко написать, как её подключить. И этим ограничиться, чтобы информации было не слишком много за один раз.
Особенно весело, что хорошая книга уже есть. Это даже без учёта maven by example.
В общем, я бы посоветовал новичкам изучать maven по этим двум книжкам, то статьи по мавену на хабре, к сожалению, в большинстве своём поверхностны и разные авторы по глубине охвата останавливались не сильно дальше данной статьи.
Я специально остановился на абсолютном минимуме. Тем, кто хочет научиться пользоваться maven этой статьи конечно недостаточно. Она предназначена для тех, кто хочет понять зачем нужен мавен и провести с ним первое знакомство.
Ну я в фазе новичка бы из этой статьи не понял зачем нужен maven
. Т. к. главное — что maven — это проектная модель — здесь не описано. Ну и что она включает минимально, в общем, тоже.
Про то, что в maven есть такая сущность как проект — есть. Про структуру проекта в maven тоже есть. Минимальный помник есть. Что означают обязательные строки в этом помнике — есть. Есть даже про то, что IDE может создать проект в собственном формате на основме pom.xml, но наверное на этом надо было сделать больший акцент.
Что ещё, по вашему мнению, нужно было добавить к минимуму?
Вы показали, как при помощи этого микроскопа забить гвоздь, который можно забить javac ом, но не показали, зачем он, maven, нужен вообще. Мне, как новичку, непонятно, а зачем надо делать вот так, именно так. Зачем структурировать проект именно таким образом и т.д.
Есть объяснение, зачем нужны систем сборки вообще. Оно очень короткое. Я опасаюсь, что если сделать его длиннее, то потеряется фокус статьи.
Как можно избежать передеплоя всего war-файла, если измеился только один class-файл?
Эклипс как-то ругнулся на Ctrl+S что, мол "… не поддерживаю hot redeploy..." но я не понял что ему нужно…
Запускать с помощью мавена не обязательно, но в статье акцент на использование мавена и поэтому я решил привести пример запуска с его помощью.
exe файл сделать вроде бы можно, но я не знаю как. Эта тема далеко за гранью рамок статьи. Можно сделать jar файл, который будет работать как exe, но это тоже в рамки статьи не входит. Коротко, как это сделать, описано grossws вот в этом комментарии.
Прямо в тему статьи: у нас (Excelsior JET) недавно еще и maven-plugin появился. ;)
https://docs.oracle.com/javase/8/docs/technotes/guides/deploy/self-contained-packaging.html
Не уверен насчет non-fx аппов — мельком видел, что без UI может глючить. Не знаю так ли это, использовал для Java FX приложения, для сервера особого смысла в принципе и нет.
хотел написать комментарий с кучей замечаний… но решил всё-таки его в личку отправить…
Впрочем пару моментов здесь опишу:
> Сразу скажу, что Java программиста, который не может собрать свою программу из консольки, на работу не возьмут
— вплоть до мидла возьмут. Умение составлять грамотные билд-файл требуется нечасто и 1-2х человек на проект хватает вполне.
> После того, как maven перестанет качать всякую дрянь из интернета
вы вроде мануал пишете? Для новичков? Ну и зачем засорять неокрепшие умы такой фигнёй? Неужели тяжело было написать что-то вроде после того, как мавен скачает зависимости и инструменты, определённые в проектном файле (а также maven-exec-plugin, к которому вы и обратились командой exec:java)"
А ещё можно было рассказать, что можно разом mvn compile exec:java -Dexec.mainClass=«com.app.HelloWorld»
Спасибо за рекомендации. Я думаю, что то, что вы написали в личку нужно было писать в коментарии. Это интересно всем, не только мне.
вы вроде мануал пишете? Для новичков? Ну и зачем засорять неокрепшие умы такой фигнёй?
Мой подход к тому, что такое "засорять" отличается от вашего. Добавлять в статью термины зависимости, инструменты и плагин — когда они в ней по сути не используются — это на мой взгляд неправильно. Я хотел написать, что мавен будет что-то качать, но это неважно — не обращайте внимание, главное что он запустит код.
Оно означает, что артифакт нестабилен и может измениться без изменения версии. Мавен понимает, что это может произойти и обновляет артифакт при каждой сборке.
Действительно не при каждой, это ценное замечание, я сильно упрощаю. SNAPSHOT версии будут обновляться, если с момента предыдущего получения зависимости из удалённого репозитория и до текущего запуска maven прошло больше суток. Интервал можно настраивать через repository->shapshots->updatePolicy.
Опция -U обновит снепшоты принудительно, независимо от интервалов и всего такого.
Нет ли в тексте ошибки?
Если у насpackage com.app;
То, вероятно, должно быть
<groupId>com.app</groupId>
Как собрать простейшую Java программу с помощью Maven