Перейти к основному содержимому

Gradle Groovy DSL — первая сборка

Разработчику

Gradle Groovy DSL — первая сборка​

Gradle — система сборки для JVM (и не только) — компиляция, тесты, упаковка JAR, запуск приложения. Сценарий описывают в build.gradle (язык Groovy) или build.gradle.kts (Kotlin).

Android и многие enterprise-репозитории до сих пор используют Groovy DSL. Строка implementation 'group:artifact:version' внутри dependencies { } — это вызов метода, который Gradle добавляет через делегирование замыканий, а не "магический" синтаксис.

Java-аналог на Kotlin DSL: Gradle — практический старт. Maven: структура и сборки Java. Тесты Spock: Spock — первая спецификация. CI: Jenkinsfile.


Что получится​

Проект hello-groovy-gradle: ./gradlew build, JAR, unit-тест. Понимание блоков plugins, repositories, dependencies, tasks.

./gradlew build

Разбор:

  • Фрагмент на bash показывает рабочий пример: начинается с ./gradlew build и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Термины​

ТерминПростыми словами
ПроектКорень с build.gradle или подпапка в multi-module
Плагин (plugin)Набор готовых задач (java, application)
Задача (task)Единица работы: compileJava, test, build
Конфигурацияimplementation, testImplementation — "роль" зависимости
Wrapper (gradlew)Скрипт, который скачивает фиксированную версию Gradle
Maven CentralПубличный репозиторий JAR-файлов
ToolchainGradle сам подберёт JDK нужной версии

Groovy DSL и Kotlin DSL​

Groovy build.gradleKotlin build.gradle.kts
Исторически в AndroidНовые модули часто на KTS
Больше примеров в сетиСтроже подсказки IDE
Один и тот же Gradle "под капотом"Один и тот же Gradle

Логика одинакова; меняется только синтаксис файла.


Создание проекта​

mkdir hello-groovy-gradle && cd hello-groovy-gradle
gradle init

Разбор:

  • mkdir ... && cd ... — создаёт каталог проекта и переходит в него (одна строка в shell).
  • gradle init — мастер Gradle — предложит тип проекта (application), язык (Java), DSL скрипта (Groovy).
  • После мастера появятся build.gradle, settings.gradle, wrapper — их коммитят в Git.
  • Глобальный gradle нужен только для init; дальше команда — ./gradlew.
  • Без wrapper коллеги и CI получат другую версию Gradle и "плавающие" сборки.

Минимальный build.gradle вручную (если не используете gradle init):

Код ITЗагрузка примера кода…

Разбор:

  • plugins { id 'java' } — подключает компиляцию src/main/java, тесты, задачу jar.
  • repositories { mavenCentral() } — откуда Gradle скачивает JAR-зависимости.
  • implementation — библиотека для основного кода; groovy на classpath компиляции и runtime.
  • tasks.named('test') { useJUnitPlatform() } — тесты через JUnit 5 (нужно для JUnit и Spock 2.x).
  • Для запуска main добавьте плагин application и блок application { mainClass = '...' } (см. полный пример ниже).

Разбор:

  • Фрагмент на bash показывает рабочий пример: начинается с mkdir hello-groovy-gradle && cd hello-groovy-gradle и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

В мастере выберите — application, Java, Groovy build script, JUnit Jupiter.

Появятся:

ФайлНазначение
gradlew, gradlew.batWrapper для Unix/Windows
gradle/wrapper/gradle-wrapper.propertiesВерсия Gradle
settings.gradleИмя и список подпроектов
build.gradleСценарий сборки

settings.gradle​

rootProject.name = 'hello-groovy-gradle'

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с rootProject.name = 'hello-groovy-gradle' и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Имя корневого проекта влияет на имя JAR и отображение в IDE. В multi-module сюда добавляют include 'api', 'service'.


build.gradle — разбор по блокам​

Код ITЗагрузка примера кода…

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с plugins { и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы функций или команд выполняют полезное действие: чтение данных, вычисление результата или запуск задачи сборки.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Таблица блоков​

БлокНазначение
plugins { id 'java' }Задачи компиляции, тестов, JAR
plugins { id 'application' }Задача run с точкой входа
group / versionКоординаты артефакта (Maven-style)
repositories { mavenCentral() }Откуда скачивать зависимости
dependencies { ... }Список библиотек по конфигурациям
application { mainClass = ... }Класс с public static void main
java { toolchain { ... } }Сборка под JDK 17 без ручного JAVA_HOME
tasks.named('test') { useJUnitPlatform() }JUnit 5 вместо устаревшего JUnit 4

Конфигурации зависимостей​

КонфигурацияКуда попадает JAR
implementationТолько ваш модуль при компиляции и runtime
testImplementationТолько тесты (src/test)
api (в библиотеках)Пробрасывается потребителям модуля

Правило для новичка: production-код → implementation, тестовые библиотеки (JUnit, Spock) → testImplementation.

Строка 'org.apache.groovy:groovy:4.0.21' — координата Maven: group:artifact:version.

Почему implementation '...' работает внутри { } — см. делегирование DSL.


Структура каталогов (Java)​

src/main/java/ — production
src/test/java/ — JUnit
src/test/groovy/ — Spock (если подключили)

Разбор:

  • Фрагмент на text показывает рабочий пример: начинается с src/main/java/ — production и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы функций или команд выполняют полезное действие: чтение данных, вычисление результата или запуск задачи сборки.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

src/main/java/com/example/App.java:

package com.example;

public class App {
public static void main(String[] args) {
System.out.println("Hello from Gradle Groovy DSL");
}
}

Разбор:

  • Фрагмент на java показывает рабочий пример: начинается с package com.example; и задает контекст выполнения.
  • Конструкция class описывает структуру объекта: поля хранят состояние, а методы инкапсулируют поведение.
  • Вызовы методов и объявления функций задают основной шаг логики: входные значения передаются в метод и сразу обрабатываются.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Пакет com.example должен совпадать с путём папок.


Команды​

./gradlew tasks # список задач
./gradlew compileJava # только компиляция main
./gradlew test # компиляция + тесты
./gradlew run # запуск main (плагин application)
./gradlew build # compile + test + jar

Разбор:

  • Фрагмент на bash показывает рабочий пример: начинается с ./gradlew tasks # список задач и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы функций или команд выполняют полезное действие: чтение данных, вычисление результата или запуск задачи сборки.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Wrapper: gradlew фиксирует версию Gradle из gradle-wrapper.properties. В CI и у коллег не нужно ставить Gradle глобально — коммитьте wrapper в Git.

Windows: gradlew.bat вместо ./gradlew.


Своя задача (task)​

tasks.register('hello') {
group = 'custom'
description = 'Печать приветствия'
doLast {
println "Gradle task hello"
}
}

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с tasks.register('hello') { и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы функций или команд выполняют полезное действие: чтение данных, вычисление результата или запуск задачи сборки.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.
ЧастьСмысл
tasks.register('hello')Ленивая регистрация задачи
group / descriptionОтображение в ./gradlew tasks
doLast { }Closure: выполнится в конце задачи
./gradlew hello

Разбор:

  • Фрагмент на bash показывает рабочий пример: начинается с ./gradlew hello и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Встроенные задачи плагина java устроены так же: цепочка doFirst / doLast и зависимости между задачами (test зависит от compileTestJava).


Подключение Spock​

dependencies {
testImplementation 'org.spockframework:spock-core:2.3-groovy-4.0'
testImplementation 'org.apache.groovy:groovy:4.0.21'
}

test {
useJUnitPlatform()
}

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с dependencies { и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы функций или команд выполняют полезное действие: чтение данных, вычисление результата или запуск задачи сборки.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Тесты в src/test/groovy — см. Spock — первая спецификация.


Multi-module (набросок)​

settings.gradle:

rootProject.name = 'parent'
include 'api', 'service'

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с rootProject.name = 'parent' и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

У api/ и service/ свой build.gradle. Зависимость модуля на модуль:

dependencies {
implementation project(':api')
}

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с dependencies { и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы функций или команд выполняют полезное действие: чтение данных, вычисление результата или запуск задачи сборки.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Сборка всего дерева: ./gradlew build из корня.

./gradlew build

Разбор:

  • Фрагмент на bash показывает рабочий пример: начинается с ./gradlew build и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Частые ошибки​

СимптомПричина
Could not find method implementation()Не применён плагин java
Unsupported class file major versionToolchain ниже версии байткода зависимости
gradlew не найден в CIЗапускают gradle без wrapper — добавьте wrapper в репо
Тесты не запускаютсяНет useJUnitPlatform() для JUnit 5

Что попробовать​

  1. Добавить Spock и один CalcSpec.
  2. Spring Boot plugin — сравнить с Первая программа на Spring Framework.
  3. Переписать скрипт в Kotlin DSL — Gradle — практический старт.
  4. Подключить Jenkins с ./gradlew test.
./gradlew test

Разбор:

  • Фрагмент на bash показывает рабочий пример: начинается с ./gradlew test и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Дальше​

Spock · Jenkinsfile · делегирование DSL


Реальный workflow команды с Gradle​

Типичный ежедневный цикл:

  1. Локально запускаем ./gradlew test.
  2. Перед пушем делаем ./gradlew build.
  3. В CI повторяем тот же wrapper-командой.
  4. Для релиза добавляем версионирование и публикацию.
./gradlew clean test build

Разбор:

  • Фрагмент на bash показывает рабочий пример: начинается с ./gradlew clean test build и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Одинаковые команды локально и в CI снижают число "у меня работает" случаев.


Производительность сборки​

Для ускорения больших проектов применяют:

  • org.gradle.caching=true в gradle.properties;
  • org.gradle.parallel=true для независимых модулей;
  • remote build cache в CI;
  • разделение модулей, чтобы изменения в одном модуле не пересобирали все дерево.
org.gradle.caching=true
org.gradle.parallel=true

Разбор:

  • Фрагмент на properties показывает рабочий пример: начинается с org.gradle.caching=true и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Основная логика выражена последовательностью инструкций, которые рантайм выполняет сверху вниз.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Оптимизацию проверяют через build scan и время критичных задач (compileJava, test).


Мини-памятка по качеству build.gradle​

  • Плагины и версии вынесены в единый каталог версий или convention plugins.
  • Зависимости группируются по назначению.
  • Кастомные задачи имеют group и description.
  • Wrapper хранится в репозитории и обновляется осознанно.

Связанные материалы — Jenkins Pipeline, Spock, Groovy и Java.


Сквозной кейс — build.gradle для каталога​

Сборка каталога книг в едином файле:

Код ITЗагрузка примера кода…

Разбор:

  • Фрагмент на groovy показывает рабочий пример: начинается с plugins { и задает контекст выполнения.
  • Ключевые операторы и выражения (def, литералы, вызовы) формируют данные, с которыми работает остальная часть примера.
  • Вызовы функций или команд выполняют полезное действие: чтение данных, вычисление результата или запуск задачи сборки.
  • Поток выполнения линейный: шаги идут последовательно, поэтому итог зависит от порядка операций в блоке.
  • Итог фрагмента — воспроизводимый результат — вывод в консоль, изменение данных или артефакт, который можно сразу проверить.

Дальше тот же сценарий везде:

  • локально ./gradlew test;
  • в Jenkins тот же wrapper;
  • отчеты подхватываются через junit.

Этот шаг закрывает сквозной маршрут "модель → логика → БД → тесты → CI".