Введение
Темой данного обзора будет система автоматической сборки 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
Сразу хочется отметить, что 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 специальный враппер - это такой специальный скрипт. Про него подробнее советую прочитать в официальной документации — "
The Gradle Wrapper".
Во-вторых, мы видим Gradle Build Script – файл build.gradle. Это – главный файл, в котором описывается то, какие библиотеки и фрэймворки использует наш проект, какие плагины нужно подключить к проекту и описывает различные таски. Подробнее про данный файл советую прочитать в официальной документации: "
Build Script Basics".
Plugins и Tasks
Если посмотреть сейчас на на содержимое Build Script, то мы увидим секцию plugins:
plugins {
id 'java'
id 'application'
}
Это те самые плагины, про которые мы говорили ранее. А если есть плагины, то есть и задачи, которые нам теперь доступны. Мы можем выполнить команду gradle tasks и увидеть, что мы сейчас можем сделать с проектом:
Например, выполнив
gradle run
мы запустим main класс нашего java приложения:
Как мы видим, снизу написано так же
2 actionable tasks: 1 executed, 1 up-to-date
Что это значит? Это значит, что всего было выполнено 2 таска: Причём 1 действительно выполнен, а один не выполнялся, т.к. он up-to-date, то есть состояние актуальное и ничего выполнено не было.
Мы можем выполнить так называемый "Dry Run":
gradle run -m
Выполним эту команду, мы увидим, какие будут выполнены таски, чтобы выполнить таск run:
Как мы видим, всего было выполнено целых 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).
Про задачи так же следует прочитать:
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 – является отличным выбором в качестве систем сборки проектов. Подтверждением тому является то, что его используют разработчики таких известных проектов, как Spring и Hibernate. Выше были рассмотрены лишь самые базовые вещи. За ними скрыт миллион особенностей и возможностей, которые появляются у разработчиков. Gradle так же поддерживает создание многомодульных проектов, что не рассмотрено в данном обзоре, но есть отличный tutorial у самого Gradle: "
Creating Multi-project Builds".
Надеюсь, данный обзор так же продемонстрировал, что документация у Gradle написана на 5+ и по ней легко можно найти нужное, если понимать, куда примерно смотреть. А это придёт, когда понимаешь основы. Кроме того, у Gradle шикарные tutorial.
Закончить хочется небольшим списком того, что ещё можно посмотреть по Gradle:
#Viacheslav
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ