1. Обзор
Gradle — это система управления сборкой на основе Groovy, разработанная специально для создания проектов на основе Java.
Инструкции по установке можно найти здесь .
2. Строительные блоки – проекты и задачи
В Gradle сборки состоят из одного или нескольких проектов, а каждый проект состоит из одной или нескольких задач.
Проектом в Gradle может быть сборка jar
, war
или даже zip
- файла.
Задача — это отдельная работа. Это может включать компиляцию классов или создание и публикацию Java/веб-архивов.
Простую задачу можно определить так:
task hello {
doLast {
println 'ForEach'
}
}
Если мы выполним вышеуказанную задачу с помощью команды gradle -q hello
из того же места, где находится build.gradle
, мы должны увидеть вывод в консоли.
2.1. Задачи
Сценарии сборки Gradle — это не что иное, как Groovy:
task toLower {
doLast {
String someString = 'HELLO FROM FOREACH'
println "Original: "+ someString
println "Lower case: " + someString.toLowerCase()
}
}
Мы можем определить задачи, которые зависят от других задач. Зависимость задачи можно определить, передав аргумент dependOn: имя_задачи
в определении задачи:
task helloGradle {
doLast {
println 'Hello Gradle!'
}
}
task fromForEach(dependsOn: helloGradle) {
doLast {
println "I'm from ForEach"
}
}
2.2. Добавление поведения к задаче
Мы можем определить задачу и улучшить ее с помощью некоторого дополнительного поведения:
task helloForEach {
doLast {
println 'I will be executed second'
}
}
helloForEach.doFirst {
println 'I will be executed first'
}
helloForEach.doLast {
println 'I will be executed third'
}
helloForEach {
doLast {
println 'I will be executed fourth'
}
}
doFirst
и doLast
добавляют действия вверху и внизу списка действий соответственно и могут быть определены несколько раз в одной задаче .
2.3. Добавление свойств задачи
Мы также можем определить свойства:
task ourTask {
ext.theProperty = "theValue"
}
Здесь мы устанавливаем «Значение»
как свойство
задачи ourTask
. ``
3. Управление плагинами
В Gradle есть два типа плагинов — скриптовые
и бинарные.
Чтобы воспользоваться дополнительными функциями, каждый плагин должен пройти две фазы: разрешение
и применение.
Разрешение
означает поиск правильной версии jar плагина и добавление ее в путь к классам
проекта.
Применение
плагинов — это выполнение Plugin.apply(T)
в проекте .
3.1. Применение плагинов скриптов
В aplugin.gradle
мы можем определить задачу:
task fromPlugin {
doLast {
println "I'm from plugin"
}
}
Если мы хотим применить этот плагин к нашему файлу build.gradle
проекта , все, что нам нужно сделать, это добавить эту строку в наш build.gradle
:
apply from: 'aplugin.gradle'
Теперь выполнение команды gradle tasks
должно отображать задачу fromPlugin
в списке задач.
3.2. Применение бинарных плагинов с помощью плагинов DSL
В случае добавления основного двоичного плагина мы можем добавить короткие имена или идентификатор плагина:
plugins {
id 'application'
}
Теперь задача запуска из подключаемого модуля
приложения
должна быть доступна в проекте для запуска любого исполняемого файла
jar. Чтобы применить плагин сообщества, мы должны указать полный идентификатор плагина:
plugins {
id "org.shipkit.bintray" version "0.9.116"
}
Теперь задачи Shipkit
должны быть доступны в списке задач gradle
.
Ограничения плагинов DSL:
- Он не поддерживает код Groovy внутри блока
плагинов .
Блок plugins
должен быть оператором верхнего уровня в сценариях сборки проекта ( перед ним разрешен толькоблок buildscripts{} )
- Плагины DSL не могут быть записаны в плагинах скриптов, файле
settings.gradle
или в скриптах инициализации
Плагины DSL все еще находятся в стадии разработки. DSL и другая конфигурация могут измениться в более поздних версиях Gradle.
3.3. Устаревшая процедура применения плагинов
Мы также можем применять плагины с помощью «apply plugin»
:
apply plugin: 'war'
Если нам нужно добавить плагин сообщества, мы должны добавить внешний jar-файл в путь к классам сборки, используя блок buildscript{}
.
Затем мы можем применить плагин в сценариях сборки, но только после любого существующего блока plugins{}
:
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "org.shipkit:shipkit:0.9.117"
}
}
apply plugin: "org.shipkit.bintray-release"
4. Управление зависимостями
Gradle поддерживает очень гибкую систему управления зависимостями, она совместима с широким спектром доступных подходов.
Лучшие практики управления зависимостями в Gradle — управление версиями, динамическое управление версиями, разрешение конфликтов версий и управление транзитивными зависимостями.
4.1. Конфигурация зависимостей
Зависимости сгруппированы в разные конфигурации. У конфигурации есть имя, и они могут расширять друг друга .
Если мы применим подключаемый модуль Java, у нас будут конфигурации compile, testCompile, runtime
, доступные для группировки наших зависимостей. Конфигурация по умолчанию
расширяет « время выполнения».
4.2. Объявление зависимостей
Давайте рассмотрим пример добавления некоторых зависимостей (Spring и Hibernate) несколькими разными способами:
dependencies {
compile group:
'org.springframework', name: 'spring-core', version: '4.3.5.RELEASE'
compile 'org.springframework:spring-core:4.3.5.RELEASE',
'org.springframework:spring-aop:4.3.5.RELEASE'
compile(
[group: 'org.springframework', name: 'spring-core', version: '4.3.5.RELEASE'],
[group: 'org.springframework', name: 'spring-aop', version: '4.3.5.RELEASE']
)
testCompile('org.hibernate:hibernate-core:5.2.12.Final') {
transitive = true
}
runtime(group: 'org.hibernate', name: 'hibernate-core', version: '5.2.12.Final') {
transitive = false
}
}
Мы объявляем зависимости в разных конфигурациях: compile
, testCompile
и runtime
в разных форматах.
Иногда нам нужны зависимости, которые имеют несколько артефактов. В таких случаях мы можем добавить нотацию только для артефакта @extensionName
(или ext
в развернутом виде) для загрузки нужного артефакта:
runtime "org.codehaus.groovy:groovy-all:2.4.11@jar"
runtime group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.4.11', ext: 'jar'
Здесь мы добавили нотацию @jar
, чтобы загружать только артефакт jar без зависимостей.
Чтобы добавить зависимости к любым локальным файлам, мы можем использовать что-то вроде этого:
compile files('libs/joda-time-2.2.jar', 'libs/junit-4.12.jar')
compile fileTree(dir: 'libs', include: '*.jar')
Когда мы хотим избежать транзитивных зависимостей, мы можем сделать это на уровне конфигурации или на уровне зависимостей :
configurations {
testCompile.exclude module: 'junit'
}
testCompile("org.springframework.batch:spring-batch-test:3.0.7.RELEASE"){
exclude module: 'junit'
}
5. Мультипроектные сборки
5.1. Жизненный цикл сборки
На этапе инициализации Gradle определяет, какие проекты будут участвовать в многопроектной сборке.
Обычно это упоминается в файле settings.gradle
, который находится в корне проекта. Gradle также создает экземпляры участвующих проектов.
На этапе настройки все созданные экземпляры проектов настраиваются на основе конфигурации функций Gradle по требованию.
В этой функции только необходимые проекты настраиваются для выполнения конкретной задачи. Таким образом, время настройки значительно сокращается для большой многопроектной сборки. Эта функция все еще находится в стадии разработки.
Наконец, на этапе выполнения выполняется подмножество задач, созданных и настроенных. Мы можем включить код в файлы settings.gradle
и build.gradle
, чтобы воспринимать эти три этапа.
В настройках.градле
:
println 'At initialization phase.'
В build.gradle
:
println 'At configuration phase.'
task configured { println 'Also at the configuration phase.' }
task execFirstTest { doLast { println 'During the execution phase.' } }
task execSecondTest {
doFirst { println 'At first during the execution phase.' }
doLast { println 'At last during the execution phase.' }
println 'At configuration phase.'
}
5.2. Создание мультипроектной сборки
Мы можем выполнить команду gradle init
в корневой папке, чтобы создать скелет для файлов settings.gradle
и build.gradle
.
Вся общая конфигурация будет храниться в корневом скрипте сборки:
allprojects {
repositories {
mavenCentral()
}
}
subprojects {
version = '1.0'
}
Файл настроек должен включать имя корневого проекта и имя подпроекта:
rootProject.name = 'multi-project-builds'
include 'greeting-library','greeter'
Теперь нам нужно иметь пару папок подпроектов с именами приветствие-библиотека
и приветствие
, чтобы иметь демонстрацию многопроектной сборки. Каждый подпроект должен иметь отдельный сценарий сборки для настройки своих индивидуальных зависимостей и других необходимых конфигураций.
Если мы хотим, чтобы наш проект приветствия
зависел от библиотеки приветствия
, нам нужно включить эту зависимость в скрипт сборки приветствия
:
dependencies {
compile project(':greeting-library')
}
6. Использование Gradle-обертки
Если в проекте Gradle есть файл gradlew
для Linux и файл gradlew.bat
для Windows, нам не нужно устанавливать Gradle для сборки проекта.
Если мы выполним сборку
gradlew
в Windows и сборку ./gradlew
в Linux, дистрибутив Gradle, указанный в файле gradlew
, будет загружен автоматически.
``
Если мы хотим добавить оболочку Gradle в наш проект:
gradle wrapper --gradle-version 4.2.1
Команду необходимо выполнить из корня проекта. Это создаст все необходимые файлы и папки для привязки оболочки Gradle к проекту. Другой способ сделать то же самое — добавить задачу-оболочку в скрипт сборки:
task wrapper(type: Wrapper) {
gradleVersion = '4.2.1'
}
Теперь нам нужно выполнить задачу- обертку
, и задача привяжет наш проект к обертке. Помимо файлов gradlew
, внутри папки gradle создается папка-
оболочка
, содержащая jar и файл свойств.
Если мы хотим перейти на новую версию Gradle, нам нужно всего лишь изменить запись в gradle-wrapper.properties
.
7. Заключение
В этой статье мы рассмотрели Gradle и увидели, что он обладает большей гибкостью по сравнению с другими существующими инструментами сборки с точки зрения разрешения конфликтов версий и управления транзитивными зависимостями.
Исходный код этой статьи доступен на GitHub .