W3docs

Введение в Gradle для Java

Что такое Gradle, чем он отличается от Maven и как настроить проект Java с помощью Gradle.

Gradle — это инструмент автоматизации сборки для JVM (и не только), который компилирует код, запускает тесты, управляет зависимостями и упаковывает результат — всё это управляется скриптом сборки, написанным на Groovy или Kotlin. Там, где Maven описывает проект фиксированным XML, Gradle описывает его кодом: скрипт сборки конфигурирует граф задач. Именно этот переход к программируемой модели в сочетании с инкрементальным кешем сборки, пропускающим уже выполненную работу, сделал Gradle основным инструментом для Android и многих крупных Java-проектов.

Gradle vs. Maven

Оба инструмента решают одну задачу — воспроизводимые сборки с управляемыми зависимостями — но делают разные компромиссы. Если вы уже знакомы с Maven, вот сравнительная таблица:

АспектMavenGradle
Файл сборкиpom.xml (XML)build.gradle (Groovy) или build.gradle.kts (Kotlin)
МодельФиксированные фазы жизненного циклаНастраиваемый граф задач (DAG)
РасширяемостьПлагины, привязанные к фазамПлагины и встроенные ad-hoc-задачи
Инкрементальная сборкаОграниченаПолноценная: проверка актуальности + кеш сборки
Обёртканеобязательнаgradlew — стандарт, фиксирует версию Gradle
МногословностьБольше шаблонного кодаЛаконичнее, но больше «магии» для изучения

Ни один из них не является однозначно лучшим. Жёсткость Maven делает сборки предсказуемыми; гибкость Gradle позволяет выражать сложные сборки. В этой части рассматривается Gradle; введение в Maven охватывает другую сторону.

Минимальный скрипт сборки Java

Проект Java на Gradle — это один файл build.gradle и стандартная структура исходников (src/main/java, src/test/java). Подключение встроенного плагина java обучает Gradle компилировать, тестировать и создавать jar:

plugins {
    id 'java'
}

group = 'com.example'
version = '1.0.0'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.google.guava:guava:33.0.0-jre'
    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
}

Kotlin DSL (build.gradle.kts) выражает то же самое с типобезопасными аксессорами:

plugins {
    java
}

dependencies {
    implementation("com.google.guava:guava:33.0.0-jre")
    testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
}

Задачи как единица работы

Всё, что делает Gradle, — это задача: compileJava, test, jar, build. Задачи объявляют зависимости от других задач, образуя направленный ациклический граф (DAG). Когда вы запускаете gradle build, Gradle обходит этот граф и выполняет каждое предусловие ровно один раз в нужном порядке. Вы также можете определять собственные задачи:

task hello {
    doLast {
        println 'Hello from a custom Gradle task'
    }
}

task release {
    dependsOn 'build', 'hello'
}

Плагин java автоматически выстраивает стандартный граф: classes зависит от compileJava и processResources; jar зависит от classes; test зависит от classes и compileTestJava; build зависит от jar и test. Таким образом, запрос build выполняет все задачи в порядке зависимостей.

Обёртка и командная строка

Gradle Wrapper (gradlew / gradlew.bat) — это встроенный в проект скрипт, который загружает и запускает именно ту версию Gradle, которую ожидает проект, так что участникам не нужно устанавливать Gradle глобально:

./gradlew build          # compile, test, and package
./gradlew test           # run tests only
./gradlew clean build    # wipe outputs, then rebuild from scratch
./gradlew tasks          # list available tasks
./gradlew dependencies   # print the resolved dependency tree

Использование ./gradlew вместо системного gradle является рекомендуемым стандартом — это делает сборку воспроизводимой на любых машинах и в CI.

Практический пример: граф задач, разрешённый как в Gradle

На этой странице нет Gradle, поэтому вместо реальной сборки мы моделируем основной движок Gradle на чистом Java: граф задач с зависимостями, разрешаемый в порядок выполнения с помощью топологической сортировки — именно это делает Gradle, когда вы вводите gradle build. Второй проход показывает, как актуальные задачи пропускаются, что и является инкрементальной сборкой Gradle.

java— editable, runs on the server

Что можно вынести из запуска:

  • Сборка объявляет 7 задач, но вы никогда не указываете порядок вручную — вы запрашиваете build, а граф вычисляет остальное. Эта инверсия (объявляй зависимости, позволь инструменту упорядочить) — суть модели задач Gradle.
  • Разрешённый порядок выводит сначала compileJava и processResources, затем classes, jar, compileTestJava, test и наконец build. Задача запускается только после всех задач, от которых зависит, — именно поэтому компиляция предшествует упаковке, а тесты — build.
  • classes достигается через два пути (через jar и через test), но появляется в порядке один раз — множество done гарантирует, что каждая задача выполняется единожды, точно так же как Gradle никогда не перекомпилирует одни и те же источники дважды в одном вызове.
  • При втором запуске три задачи, помеченные как актуальные, выводят (UP-TO-DATE) и не засчитываются; только jar, compileTestJava, test и build показывают (EXEC). Это и есть инкрементальная сборка Gradle: задачи, входные данные которых не изменились, пропускаются.
  • Итоговая строка сообщает о выполнении 4 из 7 задач. Пропуск неизменённой работы — именно поэтому второй запуск gradle build значительно быстрее первого, и именно поэтому кеш сборки важен в крупных проектах.

Что охватывает остальная часть этого раздела

Написание реальных скриптов build.gradle, объявление и разрешение зависимостей из Maven Central, применение и настройка плагинов, определение пользовательских задач и использование обёртки в CI. Следующая глава, Сборка проекта Java с Gradle, настраивает полноценный проект Java с Gradle с нуля.

Практика

Практика
Когда вы запускаете 'gradle build', как Gradle определяет порядок выполнения задач compileJava, test и jar?
Когда вы запускаете 'gradle build', как Gradle определяет порядок выполнения задач compileJava, test и jar?
Was this page helpful?