В данной статье разберемся в практических различиях инструментов для сборки Maven и Gradle. Ведь современным разработчикам катастрофически не хватает времени на погружение во все технологии. Иногда нет времени, что бы прочитать несколько сотен страниц документации по каждому инструменту. Например, на первой работе меня постоянно преследовал стресс из-за того, что я не знаю почти все, что касается настройки и запуска проекта. Так получилось, что с проекта уходил последний java-разработчик. Я должен был принять проект и вести его вместе с другим фронтенд-разработчиком. Я потратил кучу времени на локальный запуск проекта. Но когда все получилось, я закрыл много задач по проекту и получил бесценный опыт. В этой статье я попытаюсь резюмировать свой опыт, который поможет разобраться в сборке многомодульных проектов.

Сначала рассмотрим Maven и его неочевидные настройки, а потом перейдем к Gradle. Для меня Maven оказался проще по сравнению с Gradle, потому что все настройки собраны в одном файле pom.xml. В официальной документации говорится "как только вы ознакомитесь с одним проектом Maven, вы поймете, как строятся все проекты Maven". Это действительно так, но есть пару нюансов. Как правило, приходится вести несколько проектов и все проекты будут хранить зависимости в виде jar-файлов в одном репозитории. Это приводит к тому, что зависимости с более высокой версией будут удалять старые jar-файлы. Это приводит к ошибкам во время сборки проекта.

В таких случаях необходимо настроить отдельный локальный репозиторий для каждого проекта. В настройках Intellij Idea есть вкладка "Build, Execution, Deployment", далее "Build Tools" и в ней Maven. Для каждого отдельного проекта нужно определить расположение репозитория и файла settings.xml, в котором содержаться пользовательские настройки.

Допустим, у вас несколько проектов с условными названиями - project1, project2, etc. В папке .m2 создаем отдельные директории с такими же названиями, создаем внутри создаем еще одну папку repository и файл settings.xml. В моем случае файл settings создал тимлид, но если нужно создать пользовательские настройки с нуля, то проще всего скопировать глобальные настройки Maven в качестве основы и подредактировать, как будет показано ниже.

Глобальные настройки можно найти в папке conf в директории установки Мавен, если он у вас установлен. Если нет, тогда Вы можете скачать бинарный файл с сайта https://maven.apache.org/download.cgi. Итак, копируем файл settings.xml в папку project1 и начинаем его править.

Для начала можно удалить все комментарии для удобочитаемости. Таким образом, первые строки объявляют версию XML и пространство имен:

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">

Это магическая магия для тех, кто не знаком с языком XML, которая является стандартным заголовком в xml-файлах. Если не вдаваться в подробности, то внутри заголовка лежат ссылки на другие xml-файлы, в которых перечисляются так называемые "элементы" (именованные переменные), их значение и тип (напр. name="offline" type="xs:boolean"), минимальное и максимальное количество элементов (minOccurs="0" означает, что этот элемент можно не указывать, minOccurs="1" означает, что элемент нужно указать минимум 1 раз) и пр.

Далее внутри тегов <localRepository> и </localRepository> нужно указать путь до папки repository (например, C:\Users\username.m2\project1\repository). Сохраняем и закрываем файл settings.xml. Смотрим в папке /.m2 вместо одной директории repository должны лежать отдельные папки на каждый проект.

Далее возвращаемся в IDE, поочередно открываем проекты project1, project2 etc. и указываем путь до репозитория и файла настроек во вкладке Maven ("Build, Execution, Deployment" -> "Build Tools").

После этого, запускаем задачи Maven clean и install, либо нажимаем кнопку Reload All Maven Project в боковой вкладке Maven. Среда разработки закачивает в новый репозиторий все зависимости и плагины. Теперь если зайти в папку .m2/project1/repository, то можно увидеть новые папки с jar-файлами.

Когда вы закончили с настройкой репозитория, можно перейти к настройке микросервисов. В моем случае это был проект с 15 микросервисами и 14 библиотеками, т.е. это были 29 отдельных проектов со своими pom.xml файлами. И даже если вы знакомы с Maven по учебным проектам, то не сразу можно догадаться, как настроить несколько Maven-проектов, что бы они работали вместе и открывались как один проект.

Сначала нужно найти основной проект (в моем случае это был пустой проект с файлами pom.xml и README.md, без без src). Открываем его в среде разработки Idea, раскрываем вкладу Maven и нажимаем кнопку "Add Maven Project".

Далее поочередно добавляем проекты просто выбирая соответствующие файлы pom.xml в каждом отдельном проекте. На этом настройка Maven проекта завершена.

Прим. Также я столкнулся с двумя сложностями - настройкой БД (Postgres, Liquibase) и Spring Cloud (Eureka, настройка Feign-сервисов, Kafka/Zookeeper). Эти этапы я пропущу, потому что их нужно описать в отдельной статье.

Теперь перейдем к Gradle. Когда я получил проект с gradle, то долго не мог понять, кто является главным среди всех этих gradle-файлов, то есть где аналог pom.xml в gradle-проектах. На самом деле все оказалось просто - это файл build.gradle. И что бы понять, как работает gradle, я предлагаю создать два пустых проекта - один Maven-проект и один Gradle-проект, а также выполнить пару команд, что бы получить визуальное представление о работе обоих систем сборки.

Итак, создаем две пустые директории. В первой создадим pom.xml со следующими полями:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>example</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <java-version>11</java-version>
        <maven.compiler.source>${java-version}</maven.compiler.source>
        <maven.compiler.target>${java-version}</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

Далее заходим в терминал по адресу этой папки и вводим команду mvn clean install. В директории появилась папка target с jar-файлом проекта. Теперь если открыть проект в Intellij Idea, то во вкладке External Libraries можно увидеть, что подтянулась зависимость - JUnit.

Сделаем такую же операцию с Gradle. Создаем в новой папке файл build.gradle со следующим содержанием:

plugins {
  id 'java'
}
repositories {
    mavenCentral()
}
dependencies {
  testImplementation group: 'junit', name: 'junit', version: '4.13.2'
}

Заходим в терминал по адресу этой папки и вводим команду gradle wrapper. В директории появилась две папки - .gradle и gradle (в первой хранится кэш проекта, во втором тонкий jar для gradle, который позволяет запускать gradle-команды на машинах, где не установлен Gradle) и два исполняемых файла - gradlew (для unix-систем) и gradlew.bat (для windows). Аналогично предыдущему примеру в IDE можно увидеть, что в External Libraries уже загрузилась зависимость JUnit.

Если у вас все получилось, то эти два шаблона можно использовать для разработки новых проектов, добавляя зависимости Spring Boot.

Еще одна сложность, с которой я столкнулся в в gradle-проекте, заключается в том, что нужно потратить некоторое время на изучение Groovy (я выбрал Groovy, а не Kotlin). С помощью Groovy можно написать задачи (task), т.е. такой скрипт по сборке проекта. Или можно использовать плагины, которые импортируют в проект готовые задачи. Например, apply plugin 'java' позволяет использовать такие команды как gradle compileJava, jar, javadoc etc.

Список плагинов и импортируемых задач можно посмотреть на официальном сайте Gradle. Но если у вас есть действующий проект и вас просто нужно узнать какие задачи можно выполнить, то воспользуйтесь командой gradle tasks для вывода на экран всех доступных задач с их описанием.

P.S. Переходя с удаленки в офис и обратно, я сталкивался с такой проблемой, что мои записи с готовыми командами и шпаргалками не оказывались под рукой. Есть разные пути решения этой проблемы. Я решил создать Телеграм-канал, на котором я буду публиковать свои заметки и шпаргалки по веб-разработке, а также статьи о реальном практическом опыте на коммерческих проектах.

Комментарии (34)


  1. aleks_pingvin
    06.02.2022 18:45
    +10

    Не в обиду, но очень слабая статья... Практической пользы нет.


    1. sshikov
      06.02.2022 19:28
      +4

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


      1. aleks_pingvin
        06.02.2022 19:31
        +1

        И про профили, про scope и ещё великое множество всяких штук.


    1. Semenych
      06.02.2022 20:10
      +3

      Вот да, я открыл ожидая узнать о тонкостях, ограничениях и особенностях. Например Мавен быстрее подхватывается т.к. декларативный, но на любой чих надо писат свой плагин.

      Но ничего такого нет. Два шаблонных проекта и куча субъектива.


      1. sshikov
        06.02.2022 20:51

        >на любой чих надо писать свой плагин.
        Давайте я что-ли выскажу.

        Во-первых, на мой взгляд, плагин это не так и сложно. Написав примерно один, поняв, как это делается, вы сможете их спокойно клепать сколько угодно. Ну т.е. когда мне было нужно — я их штук 10 наваял за месяц.

        А во-вторых, есть такая штука, как груви плагин внутри мавена. Он дает вам возможность запустить груви скрипт, а так как его запускает плагин, то привязан он к проекту точно так же, как и плагин. Т.е., вы указываете, когда и какой скрипт запускать. И вот эта штука спокойно решает большую часть нестандартных задач.


        1. Semenych
          06.02.2022 21:10

          ну у меня комментарий скорее не про мавен vs gradle а все же про статью.


          1. sshikov
            06.02.2022 21:16

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


            1. Semenych
              07.02.2022 11:03
              +3

              ну раз уж мы за плагины. Основная проблема с плагинами - непрозрачность и общая тяжеловесность процесса.

              Мне не нравится гредл по многим параметрам, но у него есть одно очень ценное качество. Даже для очень заморочных проектов, а поверьте я видел много страшного legacy. Можно описать процесс сборки относительно компаткно и самодостаточно. Т.е. можно прочитать один файл сверху вниз и из него понятно что и как как собирается. И его одного достаточно.

              В ситуации с плагинами, особенно если плагин это отдельный проект который сидит в отдельной репе и грузится из корпоративного artifactory который за VPN ситуация бывает сильно не стандартной.

              К сложности - в целом плагины писать проще, чем вот этот скриптовый суп на груви или котлине в гредле. Но писать вообще не проблема. Один раз написать можно вообще на чем угодно. Пофиг. А вот читать потом годами это беда.


              1. sshikov
                07.02.2022 15:28

                >непрозрачность и общая тяжеловесность процесса.
                В какой-то степени это плана за переиспользование. Ведь именно поэтому оно в отдельном проекте в репозитории.

                Опять же, могу посоветовать посмотреть на gmaven+. Возможно вам и понравится.


                1. Semenych
                  07.02.2022 16:21

                  ну в переиспользование в 2022 году я верю слабо. Никто не любит переиспользовать.

                  На gmaven+ посмотрю, спасибо большое


                1. Semenych
                  07.02.2022 16:27

                  Хороший пример того, почему выигрывает gradle

                  посмотрите сюда https://github.com/groovy/GMavenPlus/wiki/Examples

                  даже у меня при том что я видел много разной фигни глаз от такого дергается.

                  Я понимаю, что тут достаточно стройно и четко расписано что к чему. Но вот "продать" это новому поколению разработчиков я не берусь.


                  1. sshikov
                    07.02.2022 18:10

                    Вы просто слегка не туда смотрите. Execute Scripts — это практически все, что нужно человеку, который не пишет на груви сам. Остальное — для совместимости, шоб було.


    1. KulakovAngel
      07.02.2022 08:43

      Не соглашусь. Для человека, который никогда не писал на java (меня) эта статья дала представление, что лучше использовать.


    1. Graf_Duku
      07.02.2022 08:43

      Первый блин комом))

      Буду стараться


  1. Heliki
    06.02.2022 19:29
    +6

    Это приводит к тому, что зависимости с более высокой версией будут удалять старые jar-файлы

    jar-файлы перезаписываются только в том случае, если это одна и та же версия (например, вы разрабатываете проект с дефолтной версией 0.0.1-SNAPSHOT и делаете mvn install, тогда да, он будет перезаписываться. Разные версии (например, 0.0.1 и 0.0.2) прекрасно уживаются в одном репозитории и никуда не пропадают.


    1. rdo
      06.02.2022 19:53
      +2

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


    1. sshikov
      06.02.2022 20:04
      +1

      >с дефолтной версией 0.0.1-SNAPSHOT и делаете mvn install, тогда да, он будет перезаписываться
      Не факт. Из снапшота генерируется некая уникальная версия (содержащая дату сборки или номер), которая не перезаписывает предыдущую. Просто так как вы ее не знаете — вы не сможете на нее сослаться просто так. Т.е. хранится несколько таких версий, а используется по ссылке 0.0.1-SNAPSHOT всегда последняя.

      Ну и кстати — если у вас репозиторий в виде скажем Nexus (что я обычно рекомендую сделать сразу при запуске проекта), то в релизном репозитории вообще ничего перезаписываться не будет — потому что там политика такая. Вы просто такую же версию не сможете задеплоить.


  1. BasicWolf
    06.02.2022 19:50
    +4

    И самое обидное, что "vs." так и не раскрыт. Единственное, что понятно из статьи - это что в одном случае используется декларативный pom.xml, в другом - скрипт на groovy / kotlin script. А что же дальше? Какие плюсы у первого и второго?


  1. LeshaRB
    06.02.2022 21:45
    +4

    А каким боком Idea относиться к maven и gradle?

    Проекты должны собираться и без IDE

    Меня вот другое интересует

    Далее внутри тегов <localRepository> и </localRepository> нужно указать путь до папки repository (например, C:\Users\username.m2\project1\repository)

    То есть другой разработчик, забрал себе код из репозитория и должен потом менять путь на свой?


    1. sshikov
      06.02.2022 21:56

      >должен потом менять путь на свой?
      Нет конечно. Локальный репозиторий вообще нужно указывать в редчайших случаях. То что автор про это пишет — практически лишено смысла (делать локальный репозиторий под проект). В setting.xml обычно указывают репозиторий (не локальный, а Nexus), если вы собираете проект в интранете, где нет maven central вообще.


  1. odisseylm
    07.02.2022 08:43
    +2

    Эта статья модерировалась вообще или нет? Что это за мусор? Почему у меня нет прав минусовать такие бессмысленные статьи? Это хуже любой статьи для начинающего.


  1. Jekaaaaa
    07.02.2022 08:43
    -1

    можно просто сказать майвен умер. новичкам я советую просто пропустить майвен. но что бы понять суть, надо столкнуться с система где майвен просто не соберет в кучу ваш проект. у нас к примеру в одно репозитории 110 gradle subprojects.


    1. ris58h
      07.02.2022 11:00
      +1

      Сильное заявление.


      1. sshikov
        07.02.2022 15:30
        +2

        А главное — неверное. По некоторым измерениям, процентов 70 энтерпрайза на мавене. При этом лет за 10 примерно я еще не сталкивался со случаем, когда gradle нельзя было бы выкинуть без последствий и заменить мавеном. То есть, большая часть мелких проектов не использует вообще ничего, и на груви не пишут.


        1. Jekaaaaa
          07.02.2022 17:21

          в каком enterprise работаешь ты? я работаю в крупнейшем банке сша. здесь java/kotlin куда не плюнь. и знаю два десятка крупных компаний где про maven забыли. maven строго ушел в прошлое еще 3-5 лет назад. gradle превосходит его по всем параметрам. но я еще раз повторюсь. нужно столкнуться со сложным проектом где у тебя 400 jar files transitive dependencies и нужно исключать, фильтровать или force определенную версию. не имея таких требований может казать что maven чудо природы.

          попробуй в maven, вытащить resolved classpath или скажем иметь 5 различных конфигураций, или несколько test folders. километровые xml файлы. про мелкие проекты говорить нет смысла, там вообще ничего не нужно.

          что бы понять глубину и возможности gradle нужно потратить полгода, помучаться. gradlе сложный с DSL языком (это кстати они перемудрили). я бы сказал некий maven + ANT script. второй нюанс это то что .gradle файл это временной шаблон ну или граф. поскольку можно описывать события по фазам билда. большинство людей это не секут и ноют что мол не понимаю что происходит.


          1. sshikov
            07.02.2022 18:08
            +2

            >в каком enterprise работаешь ты? я работаю в крупнейшем банке сша. здесь java/kotlin куда не плюнь.
            И что? Ну так и говорите, что у вас так везде. Я с этим и спорить не стану — вот в андроид разработке тоже дофига gradle, я и с этим спорить не буду. Я могу переформулировать претензию к вашему утверждению — вы свой опыт, вполне возможно большой и т.п. слегка так обобщаете. Но не доказываете.

            >со сложным проектом где у тебя 400 jar files transitive dependencies
            Гы. У меня Хадуп экосистема. Ее авторы обожают тянуть все что в голову придет. Транзитивные зависимости на зависимостях сидят, и зависимостями погоняют. И конфликты между ними — милое дело, и многие библиотеки обратно не совместимы.
            И при этом ничего, абсолютно ничего не заставляет нас забывать мавен. Может вы его тоже просто готовить не умеете?

            >или скажем иметь 5 различных конфигураций, и
            Вот в таких случаях как раз профили и пр. фичи мавена зачастую становятся неудобны. Для андроида это кстати типично — потому что разные телефоны.

            >что бы понять глубину и возможности gradle нужно потратить полгода
            Ну, я бы так сказал — я общаюсь с ним с тех пор, как он появился. C 2009 наверное, если быть точным. Этого достаточно? При этом я все время вижу одну тенденцию — что он выпускает по релизу раз в месяц, если не чаще, и все время становится «лучше» — но при этом мне почему-то хватает мавена 3.5.4 2018 года, и эта тенденция стабильна последние лет 10.

            И в моих проектах gradle не приживается никогда — потому что я просто не строю сборки так, чтобы мне было нужно 5 разных конфигураций. И вообще строю их так, чтобы никогда не нужно было процедурное описание сборки. Только декларативное. И почему-то всегда это получается. Ну вот не нужны мне в энтерпрайзе 5 разных конфигураций. И никогда не были. Какой-то у меня неверный энтерпрайз наверное.

            Ну или мне везет, уж тут как вам больше нравится.

            А те примерно 5% потребностей, которые иногда бывают, я покрываю груви из мавена. И при этом прекрасно пользуюсь скажем gradle-ssh плагином в своих проектах, снова из мавена. А так да, умер он, конечно — но у меня вокруг человек 500 разработчиков, есть конечно энтузиасты, sbt что-то собирают, а так процентов 80 скорее всего — мавен.


            1. Jekaaaaa
              07.02.2022 18:30

              про готовить не умеете, мне понравилось. по жванецкому:) главное что у вас работает и слава богу


              1. sshikov
                07.02.2022 18:40

                Надеюсь что у вас тоже. Аргументацию вашу вполне принимаю. И спасибо на добром слове :)


  1. Makcimka132
    07.02.2022 08:43

    Что ж, не зря Gradle используется в Android Studio, хотя у обоих есть как и недостатки, как и плюсы. Статья в целом хорошая.


    1. AndanteMQ Автор
      07.02.2022 08:46

      Спасибо!


  1. Knight_Kotlin
    07.02.2022 13:15

    Мне стало интересно, что именно предпочитают использовать большинство разработчиков Gradle или Maven, я в процессе обучения всего этого “волшебства” я использую Gradle по умолчанию. У меня сложилась мнение, что Maven устаревшая технология, сейчас начинаю задумываться.


  1. kochetkov-ma
    08.02.2022 08:01
    -1

    Зачем на новом проекте использовать Maven, если есть Gradle? При использовании Maven на крупном проекте вы в конечном итоге столкнетесь с какой-нибудь мелкой проблемой, которую не решить через xml driven development, и которая в гредле решается 2мя строчками Groovy или Kotlin кода. И ещё показатель - посмотрите какой процент новых Java/Kotlin проектов на GitHub используют Gradle и Maven, доля последнего будет менее 5 процентов. В 22 году использовать Maven это как вместо Spring использовать EJB.


    1. foal
      08.02.2022 09:51

      Не нравиться XML - есть https://github.com/takari/polyglot-maven. По поводу 'столкнётесь с какой-нибудь мелкой проблемой, которую не решить` - смотрите комментарии выше. Я только могу подтвердить - я ещё не встречал проектов, в которых невозможно использовать мавен.


      1. kochetkov-ma
        08.02.2022 11:04

        В комменариях выше говорят, что пишут плагины в таком случае. Я встречался и тоже писал. А существование https://github.com/takari/polyglot-maven подтверждает мои слова.