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

Введение в Gradle

· 8 мин. чтения

Упражнение: Сложение двух чисел

Даны два неотрицательный целых числа в виде непустых связных списков. Их цифры хранятся в обратном порядке. И каждый елемент списка содержить ровно одну цифру. Сложите эти два числа и верните сумму в виде связного списка ...

ANDROMEDA

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 .