Введение

Темой данного обзора будет система автоматической сборки Gradle. По английски системы сборки называются Build Tools. Краткое знакомство с Gradle - 1Зачем это вообще нужно? Ручная сборка проектов на Java довольно трудоёмкий процесс. Нужно правильно указать нужные проекту библиотеки и фрэймворки, от которых проект зависит. Здесь можно прочитать отличную статью на хабре: "Работа с Java в командной строке". Рано или поздно вы начнёте создавать какие-то скрипты для автоматизации этого процесса. А теперь представте что так делают все разработчики по всему миру и каждый пишет заново то, что кто-то уже написал для своего проекта. И тогда появились в свет системы сборки проектов, которые автоматизируют этот процесс. Кроме того, позволяют с одной стороны собрать Вам проект так, как Вы этого хотите, с другой стороны предоставляют вам более менее стандартизированные средства. Альтернативой Gradle является система автоматической сборки Maven. Эти две системы сборки с одной стороны разные, а с другой стороны имеют и ряд сходств. На эту тему на сайте Gradle есть материал: "Migrating from Maven to Gradle". Как сказано в этом руководстве, Gradle и Maven имеют разницу во взгляде на то, как собирать проект. Gradle основан на графе задач (task), которые могут зависеть друг от друга. Задачи выполняют какую-то работу. Maven же использует модель определённых фаз (phase), к которым присоединяются определённые "цели" (goals). В этих goals и выполняется какая-то работа. Однако, при таких разных подходах обе системы сборки следуют одному соглашению и управление зависимостями происходит схоже. Чтобы начать использовать Gradle необходимо его скачать. В google или в yandex вводим "Gradle Build Tool" и в первых результатах видим официальный сайт: https://gradle.org. На главной странице Gradle есть ссылка с текстом "Docs", которая ведёт на документацию Gradle. Для начала нам нужно установить (Install) Gradle, поэтому нам интересен раздел документации "Installing Gradle". Существует множество способов установки, в том числе способ "по старинке", т.е. вручную ("Installing manually"). Скачиваем согласно инструкции файл типа "binary-only", который будет иметь название вида gradle-5.1.1-bin.zip. Далее распаковываем архив и настраиваем переменную среды окружения PATH согласно инструкции. Главное, после выполнения инструкции команда gradle -v показывает версию установленного Gradle. Может возникнуть проблема с тем, что при определении расположения система найдёт Gradle не там, где Вы хотите. Поэтому, на Windows можно выполнить (на *nix есть свои аналоги): for %i in (gradle.bat) do @echo. %~$PATH:i Теперь, пожалуй, можно начинать знакомство.
Краткое знакомство с Gradle - 2

Инициализация проекта Gradle

Сразу хочется отметить, что Gradle — это про выполнение задач, называемых task (буду называть их тасками). Таски предоставляются различными плагинами (plugins). Подробнее про плагины советую прочитать в официальной документации: "Using Gradle Plugins". Есть набор "Core Plugins", которые есть всегда, когда установлен Gradle. Есть разные категории этих плагинов, но нас интересует категория "Utility". В этом наборе есть плагин "Build Init Plugin", который предоставляет таски для инициализации (Initialization) Gradle проекта. Нас интересует создание типа проекта: "java-application". Выполним Gradle таск: gradle init --type java-application Ответим попутно на некоторые вопросы, например о том, что мы хотим использовать Groovy DSL (стандартный язык описания задач для Gradle) и фрэймворк тестирования JUnit (об этом мы поговорим в другом обзоре). После создания мы получим следующий набор файлов:
Краткое знакомство с Gradle - 3
Во-первых, после инициализации мы получаем преднастроенный на нашу версию Gradle специальный враппер - это такой специальный скрипт. Про него подробнее советую прочитать в официальной документации — "The Gradle Wrapper". Во-вторых, мы видим Gradle Build Script – файл build.gradle. Это – главный файл, в котором описывается то, какие библиотеки и фрэймворки использует наш проект, какие плагины нужно подключить к проекту и описывает различные таски. Подробнее про данный файл советую прочитать в официальной документации: "Build Script Basics".
Краткое знакомство с Gradle - 4

Plugins и Tasks

Если посмотреть сейчас на на содержимое Build Script, то мы увидим секцию plugins:
plugins {
    id 'java'
    id 'application'
}
Это те самые плагины, про которые мы говорили ранее. А если есть плагины, то есть и задачи, которые нам теперь доступны. Мы можем выполнить команду gradle tasks и увидеть, что мы сейчас можем сделать с проектом:
Краткое знакомство с Gradle - 5
Например, выполнив gradle run мы запустим main класс нашего java приложения:
Краткое знакомство с Gradle - 6
Как мы видим, снизу написано так же 2 actionable tasks: 1 executed, 1 up-to-date Что это значит? Это значит, что всего было выполнено 2 таска: Причём 1 действительно выполнен, а один не выполнялся, т.к. он up-to-date, то есть состояние актуальное и ничего выполнено не было. Мы можем выполнить так называемый "Dry Run": gradle run -m Выполним эту команду, мы увидим, какие будут выполнены таски, чтобы выполнить таск run:
Краткое знакомство с Gradle - 7
Как мы видим, всего было выполнено целых 4 задачи: прежде чем выполнился run он выполнил по зависимости таск classes. Тас classes сам имеет 2 зависимости и поэтому он выполнил ещё и compileJava и processResources. Когда мы выполняем задачу, мы можем выполнить её с просмотром определённого уровня логов (уровень логирования определяет, на сколько важные сообщения мы хотим видеть). Например, мы можем выполнить gradle run -i. Это нам будет показывать в том числе информационные сообщения вида:
Task :classes UP-TO-DATE
Skipping task ':classes' as it has no actions.
Подробнее про логирование в Gradle советую обратиться к официальной документации: "Gradle Logging". Как мы видим, таск classes был пропущен, потому что он UP-TO-DATE, то есть состояние актуальное, ничего делать не надо, поэтому действий не было (no actions). Это из-за того, что по умолчанию в Gradle есть "Up-to-date checks" или так называемый инкрементальный билд. Подробнее про этот механизм можно почитать в документации Gradle: "Up-to-date checks (AKA Incremental Build)". Но этот механизм можно отключить, выполнив таск с указанием флага --rerun-tasks. Например, gradle run --rerun-tasks. Тогда мы увидим: 2 actionable tasks: 2 executed Как видно, количество выполненных тасков учитывает только первый уровень графа, то есть сам таск run и те таски, от которых он напрямую зависит, то есть classes. Таски, от которых зависит classes здесь не считаются (хотя они и выполняются, когда выполняется таск classes). Про задачи так же следует прочитать:
Краткое знакомство с Gradle - 8

Dependencies

Одной из главных задач любой системы сборки – управление зависимостями, то есть тем, какие библиотеки/фрэймворки нужны нашему проекту. Система сборки должна обеспечить их наличие в нужный момент и нужным образом собрать конечный артефакт нашего приложения. По умолчанию после gradle init для java-application мы увидим следующее содержимое в билд скрипте:
dependencies {
    implementation 'com.google.guava:guava:26.0-jre'
    testImplementation 'junit:junit:4.12'
}
Тут сразу понятно, что мы подключаем. Но без некоторого понимания непонятно, что за implementation и testImplementation? Тут надо опять обратиться к документации Gradle, благо документация у Gradle написана прекрасно. Называется это "Managing Dependency Configurations". Как сказано в документации, каждая зависимость объявляется с некоторым scope - областью, в рамках которой данная зависимость будет доступна. Этот скоуп (scope) и обозначается некоторой конфигурацией (configuration), каждая из которых имеет уникальное имя. Так же интересно, что множество Gradle плагинов добавляют предзаданные конфигурации. Чтобы узнать, какие у нас есть конфигурации можно выполнить: gradle --console plain dependencies Таким образом мы увидим список всех доступных конфигураций и относящихся к ним зависимостей. Мы можем отфильтровать этот список так, чтобы видеть только сами доступные конфигурации: gradle --console plain dependencies | find " - " Как же понять, что нам использовать? Тут немного придётся почитать. Т.к. мы используем плагин "Java", то начнём с его документации и раздела "Dependency management". Тут мы видим, что раньше была конфигурация (он же скоуп), называемая "compile" и обозначала "зависимость, нужная во время компиляции". Но потом его заменили (на англ. Superseded) на implementation. Подробнее про замену можно прочитать в разделе "API and implementation separation". Получается, эта зависимость будет на "compile classpath". Но иногда мы хотим, чтобы наша зависимость была включена в итоговый артефакт. Зачем? Например, у нас будет выполняемый jar, который должен сам в себе содержать всё необходимое. Что же тогда нам делать? Во-первых, такой поддержки "из коробки" (то есть по умолчанию, без каких-либо дополнительных действий) нет. Объясняется это тем, что каждый хочет архив собрать по своему, а Gradle старается быть минималистичным. Мы так же не можем исполльзовать jar архивы на classpath (без дополнительных манипуляций в коде), т.к. это так не работает (Подробнее см. "Oracle: Adding Classes to the JAR File's Classpath"). Поэтому, самым красивым способом является следующий код в билд скрипте:
jar {
    manifest {
        attributes 'Main-Class': 'jrgradle.App'
    }
    from configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
В настройках таска jar мы указываем то, что будет добавлено в манифест jar-файла (см. "Oracle: Setting an Application's Entry Point"). А дальше мы говорим, что все зависимости, которые нужны были для компиляции, мы их включим в jar. Альтернативой может послужить использование плагина "Gradle Shadow Plugin". Может показаться сложным, но другие плагины могут упрощать жизнь. Например, при создании веб-приложения (в отличии от обычного выполняемого java приложения) мы будем использовать особый плагин - "Gradle War Plugin", который имеет другое поведение и там жизнь наша будет проще (все нужные зависимости будут сложены в отдельный особый каталог самим плагином. Такая работа регламентируется тем, как должны быть устроены веб-приложения. Но это уже совсем другая история).
Краткое знакомство с Gradle - 9

Итоги

Gradle – является отличным выбором в качестве систем сборки проектов. Подтверждением тому является то, что его используют разработчики таких известных проектов, как Spring и Hibernate. Выше были рассмотрены лишь самые базовые вещи. За ними скрыт миллион особенностей и возможностей, которые появляются у разработчиков. Gradle так же поддерживает создание многомодульных проектов, что не рассмотрено в данном обзоре, но есть отличный tutorial у самого Gradle: "Creating Multi-project Builds". Надеюсь, данный обзор так же продемонстрировал, что документация у Gradle написана на 5+ и по ней легко можно найти нужное, если понимать, куда примерно смотреть. А это придёт, когда понимаешь основы. Кроме того, у Gradle шикарные tutorial. Закончить хочется небольшим списком того, что ещё можно посмотреть по Gradle:
Краткое знакомство с Gradle - 10
#Viacheslav