Java for Beginner
742 subscribers
709 photos
201 videos
12 files
1.15K links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Конфигурационные файлы: build.gradle, settings.gradle, gradle.properties

Gradle использует три основных файла конфигурации:

build.gradle:

Основной файл сборки, определяющий задачи, плагины и зависимости.

Пример:
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.18'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
testImplementation 'junit:junit:4.13.2'
}

В памяти: Парсится в объектную модель Gradle, включая задачи и зависимости. Динамическая компиляция Groovy/Kotlin увеличивает overhead.


settings.gradle:

Определяет структуру многомодульного проекта и настройки (например, корневое имя проекта, включенные модули).

Пример:
rootProject.name = 'my-project'
include 'module-api', 'module-core', 'module-web'

В памяти: Формирует модель проекта, включая граф модулей. Меньше по объему, чем build.gradle, но влияет на DAG.


gradle.properties:

Хранит свойства для настройки Gradle и JVM.

Пример:
org.gradle.jvmargs=-Xmx2048m
org.gradle.parallel=true
myVersion=1.0.0

В памяти: Свойства загружаются как часть конфигурации Gradle, минимально влияя на память.


Нюансы:
Храните build.gradle и settings.gradle в корне проекта, а gradle.properties — в корне или ~/.gradle.
Используйте
gradle.properties для чувствительных данных (например, ключи API) с осторожностью, предпочтительно шифруйте их.
В многомодульных проектах каждый модуль имеет свой build.
gradle, но общий settings.gradle.


Нюансы и внутренние механизмы

Управление памятью:
Gradle загружает модель проекта, задачи и зависимости в JVM. Groovy/Kotlin DSL увеличивают overhead из-за динамической компиляции.
Инкрементальность и кэширование снижают повторные вычисления, но требуют памяти для хранения хэшей и метаданных.
Настройте org.
gradle.jvmargs в gradle.properties для увеличения кучи: -Xmx2048m.

Кэширование:
Локальный кэш (~/.gradle/caches) хранит зависимости, плагины и результаты задач.
Build Cache (локальный или удаленный) минимизирует повторные сборки, но требует настройки и дискового пространства.
Очистка кэша: ./gradlew --stop и rm -rf ~/.
gradle/caches.

Производительность:
Инкрементальная сборка и --parallel ускоряют выполнение, но увеличивают пиковое потребление памяти.
Используйте --no-daemon для одноразовых сборок, чтобы избежать постоянного процесса
Gradle Daemon.

Отладка:
Флаг --info или --debug выводит подробные логи:./gradlew build --debug
Build Scans предоставляют визуальный анализ.
Используйте ./gradlew tasks для списка доступных задач.



Многомодульные проекты:
Gradle эффективно управляет модулями через settings.gradle, строя DAG для определения порядка сборки.
Используйте ./gradlew :module-name:task для выполнения задачи в конкретном модуле.


Совместимость:

Gradle требует JDK 8+ (рекомендуется 11+). Убедитесь, что JAVA_HOME указывает на правильный JDK.
Некоторые плагины Maven (например, maven-release-plugin) требуют адаптации для
Gradle (например, nebula-release-plugin).

#Java #middle #Gradle
👍3
Структура build-файла Gradle

Файл build.gradle (или build.gradle.kts) является основным конфигурационным файлом Gradle, определяющим, как собирать проект. Он состоит из ключевых блоков, которые задают плагины, репозитории, зависимости, задачи и конфигурации.

Основные элементы

Plugins:
Блок plugins определяет плагины, которые добавляют задачи, настройки и функциональность.

Пример (Groovy DSL):
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.18'
}


Пример (Kotlin DSL):
plugins {
java
id("org.springframework.boot") version "2.7.18"
}


Плагины могут быть:
Core plugins (например, java, application): встроены в Gradle.
Community plugins: загружаются из репозиториев (например, Maven Central).


В памяти: Плагины загружаются как Java-классы в JVM, увеличивая потребление памяти пропорционально их зависимостям и сложности.


Repositories:
Указывают, откуда Gradle загружает зависимости и плагины (например, Maven Central, JCenter).

Пример:
repositories {
mavenCentral()
maven { url 'https://repo.example.com' }
}


В памяти: Gradle загружает метаданные репозиториев (POM-файлы, индексы) в память для разрешения зависимостей, что требует временного увеличения ресурсов.


Dependencies:
Определяют библиотеки и модули, необходимые проекту.


Пример:
dependencies {
implementation 'org.springframework:spring-core:5.3.20'
testImplementation 'junit:junit:4.13.2'
}


Конфигурации (например, implementation, testImplementation) определяют область видимости зависимостей (аналогично scope в Maven).
В памяти: Gradle строит граф зависимостей (Directed Acyclic Graph, DAG), хранящий метаданные каждой зависимости. Это увеличивает потребление памяти, особенно для крупных проектов.



Tasks:
Задачи — это атомарные единицы работы (например, компиляция, тестирование).

Пример кастомной задачи:
task hello {
doLast {
println 'Hello, Gradle!'
}
}


Задачи могут зависеть друг от друга через dependsOn:task build(dependsOn:
['test', 'jar']) {
doLast { println 'Building project' }
}


В памяти: Каждая задача представлена как объект в JVM, содержащий конфигурацию, зависимости и действия. Gradle хранит DAG задач в памяти, что увеличивает overhead для сложных проектов.


Configurations:
Конфигурации определяют группы зависимостей для разных целей (например, implementation для компиляции, testImplementation для тестов).

Пример:
configurations {
customConfig
}
dependencies {
customConfig 'com.example:library:1.0'
}


В памяти: Конфигурации хранятся как часть графа зависимостей, добавляя метаданные для каждой группы. Это увеличивает объем памяти, особенно при использовании кастомных конфигураций.


Пример полного build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.18'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
testImplementation 'junit:junit:4.13.2'
}
tasks.register('customTask') {
doLast {
println 'Custom task executed'
}
}


В памяти: Файл build.gradle парсится в объектную модель, включающую плагины, зависимости и задачи. Groovy DSL требует загрузки Groovy-библиотек, а Kotlin DSL — Kotlin-библиотек, что увеличивает потребление памяти.


#Java #middle #Gradle #Build_gradle
👍4
Скриптовый движок (Groovy/Kotlin)

Gradle использует два языка для описания сборки:

Groovy DSL:
Основан на Groovy, динамически типизированном языке.
Преимущества: Простота, лаконичный синтаксис, широкая совместимость.
Недостатки: Ошибки могут обнаруживаться только на этапе выполнения из-за динамической типизации.


Пример:
dependencies {
implementation 'org.springframework:spring-core:5.3.20'
}


Kotlin DSL:
Основан на Kotlin, статически типизированном языке.
Преимущества: Автодополнение в IDE, раннее обнаружение ошибок, лучшая интеграция с Kotlin-проектами.
Недостатки: Более строгий синтаксис, требует знания Kotlin.


Пример:
dependencies {
implementation("org.springframework:spring-core:5.3.20")
}



В памяти: Groovy DSL компилируется динамически, загружая Groovy-библиотеки (например, groovy-all) в JVM, что увеличивает потребление памяти (около 50-100 МБ дополнительно). Kotlin DSL требует загрузки Kotlin-библиотек (kotlin-stdlib, kotlin-scripting), что добавляет аналогичный overhead, но статическая типизация снижает вероятность ошибок. Gradle кэширует результаты парсинга в ~/.gradle/caches для ускорения повторных сборок.



Gradle Project Object Model

Gradle Project Object Model (POM, не путать с Maven POM) — это внутренняя модель, представляющая проект в памяти.

Она включает:
Project: Корневой объект, содержащий свойства (group, name, version), задачи, зависимости и плагины.
Tasks: Объекты задач, связанные через DAG.
Dependencies: Граф зависимостей, организованный по конфигурациям.
Properties: Свойства проекта, доступные через ${
project.property}.
Subprojects: Для многомодульных проектов, каждый подпроект имеет свою модель.


Пример доступа:
println project.name
println project.version


В памяти: Gradle загружает модель проекта в JVM во время фазы конфигурации (см. ниже). Для многомодульных проектов каждый подпроект создает отдельную модель, увеличивая потребление памяти пропорционально количеству модулей. Кэширование метаданных в ~/.gradle/caches снижает повторные вычисления



Gradle Lifecycle Overview: Initialization → Configuration → Execution

Gradle выполняет сборку в три фазы:

Initialization:
Gradle загружает settings.gradle для определения структуры проекта (корневое имя, модули).
Создает объекты Project для корневого проекта и подпроектов.

В памяти: Загружаются settings.gradle и плагины, необходимые для инициализации. Это минимальная фаза по потреблению памяти.


Configuration:
Gradle парсит все build.gradle-файлы, создавая модель проекта и DAG задач.
Выполняются все скрипты конфигурации, даже для задач, которые не будут выполняться.
Пример: Определение зависимостей и задач в build.
gradle.
В памяти: Самая ресурсоемкая фаза, так как Gradle загружает и компилирует все скрипты, плагины и зависимости. Для крупных проектов может потребоваться несколько сотен МБ.


Execution:
Gradle выполняет задачи, указанные в командной строке (например, ./gradlew build), в порядке, определенном DAG.
Инкрементальность пропускает задачи, чьи входные/выходные данные не изменились.

В памяти: Зависит от сложности задач. Например, compileJava загружает исходные файлы и зависимости, а test — тестовые классы и фреймворки.


Нюансы:
Конфигурация выполняется всегда, даже если задачи не запускаются, что увеличивает время инициализации.
Используйте флаг --configure-on-demand для конфигурации только необходимых модулей:./gradlew build --configure-on-demand
Gradle Daemon сохраняет JVM между сборками, ускоряя повторные запуски, но увеличивая базовое потребление памяти.


#Java #middle #Gradle #Build_gradle
👍4
Gradle Properties

Gradle поддерживает свойства на разных уровнях, которые используются для настройки сборки.

Project-level:
Определяются в build.gradle или settings.gradle.

Пример:
version = '1.0.0'
ext.myProperty = 'value'


Доступ:
project.version, project.myProperty.


System-level:
Задаются через командную строку (-D) или gradle.properties.
Пример (
gradle.properties):org.gradle.jvmargs=-Xmx2048m

Доступ:
System.getProperty('org.gradle.jvmargs').

Environment-level:
Переменные окружения, доступные через System.getenv().
Пример:println System.getenv('JAVA_HOME')


Приоритет: Свойства командной строки (-D) > gradle.properties > свойства проекта > переменные окружения.
В памяти: Свойства загружаются как часть модели проекта или JVM, требуя минимальных ресурсов. Однако большое количество свойств в gradle.properties увеличивает время парсинга.



Различия Groovy DSL и Kotlin DSL
Groovy DSL
Kotlin DSL



Файл
build.gradle
build.
gradle.kts

Типизация
Динамическая
Статическая


Синтаксис
Лаконичный, гибкий
Более строгий, с явными типами


IDE-поддержка
Хорошая, но ограниченное автодополнение
Отличная, с сильным автодополнением


Пример зависимости

implementation 'org.example:lib:1.0'
implementation("org.example:lib:1.0")


Ошибки

Обнаруживаются на этапе выполнения
Обнаруживаются на этапе компиляции


Производительность
Быстрее парсинг, но больше памяти на Groovy
Медленнее парсинг, но меньше ошибок


В памяти: Kotlin DSL требует загрузки Kotlin-библиотек, что увеличивает потребление памяти на 50-100 МБ по сравнению с Groovy. Однако статическая типизация снижает вероятность ошибок, что может уменьшить затраты на отладку.


Рекомендации:

Используйте Groovy для простых проектов или совместимости с существующими скриптами.
Выберите Kotlin для новых проектов, особенно если команда использует Kotlin или требуется строгая типизация.



#Java #middle #Gradle #Build_gradle
👍3
Распределение конфигурации: build.gradle, settings.gradle, gradle.properties

build.gradle:
Содержит конфигурацию сборки: плагины, зависимости, задачи.
Один файл на модуль в многомодульных проектах.
Роль: Определяет, как собирать проект или модуль.


В памяти: Парсится в модель проекта, включая DAG задач и граф зависимостей.


settings.gradle:
Определяет структуру проекта: корневое имя, подмодули, настройки кэширования.

Пример:

rootProject.name = 'my-project'
include 'module-api', 'module-core'


Роль: Управляет инициализацией многомодульного проекта.


В памяти: Загружается первым, формируя модель проекта и граф модулей. Меньше по объему, чем build.gradle.


gradle.properties:
Хранит свойства для настройки Gradle, JVM и проекта.
Пример:

org.gradle.parallel=true
myVersion=1.0.0


Роль: Централизует глобальные настройки, доступные всем модулям.


В памяти: Загружается как часть конфигурации Gradle, минимально влияя на память.


Распределение конфигурации:
Общие настройки: Храните в gradle.properties (например, JVM-аргументы, версии).
Структура проекта: Определяйте в settings.
gradle (модули, кэш).
Логика сборки: Описывайте в build.
gradle (задачи, зависимости).

Нюансы:
Для многомодульных проектов используйте allprojects или subprojects в build.gradle для общих настроек:
allprojects {
repositories {
mavenCentral()
}
}


Храните чувствительные данные (например, ключи API) в ~/.
gradle/gradle.properties с ограниченными правами доступа.

В памяти: Конфигурационные файлы загружаются последовательно: gradle.properties → settings.gradle → build.gradle. Gradle кэширует результаты парсинга в ~/.gradle/caches, снижая overhead при повторных сборках.
Нюансы и внутренние механизмы


Управление памятью:
Gradle загружает модель проекта, задачи и зависимости в JVM. Для крупных проектов с сотнями задач и зависимостей потребление памяти может достигать 1-2 ГБ.
Groovy/Kotlin DSL увеличивают overhead из-за динамической/статической компиляции.
Gradle Daemon сохраняет JVM между сборками, ускоряя выполнение, но увеличивая базовое потребление памяти (около 200-300 МБ).
Оптимизируйте с помощью org.
gradle.jvmargs=-Xmx2048m и --no-daemon для одноразовых сборок.

Кэширование:

Локальный кэш (~/.gradle/caches) хранит зависимости, плагины и результаты задач, снижая сетевые запросы.
Build Cache (локальный или удаленный) минимизирует повторные вычисления, но требует настройки и дискового пространства.
Очистка кэша: ./gradlew --stop и rm -rf ~/.
gradle/caches.

Производительность:
Инкрементальная сборка пропускает неизмененные задачи, проверяя хэши входных/выходных данных.
Параллельное выполнение (--parallel) ускоряет многомодульные проекты, но увеличивает пиковое потребление памяти.
Используйте --configure-on-demand для сокращения времени конфигурации.


Отладка:
Флаг --info или --debug выводит подробные логи:./gradlew build --debug
Используйте ./gradlew tasks для списка задач или ./gradlew dependencies для анализа зависимостей.
Build Scans предоставляют визуальный анализ сборки.


Многомодульные проекты:
Gradle эффективно управляет модулями через settings.gradle, строя DAG для определения порядка сборки.
Выполняйте задачи для конкретного модуля: ./gradlew :module-name:build.


Совместимость:
Gradle требует JDK 8+ (рекомендуется 11+). Убедитесь, что JAVA_HOME указывает на правильный JDK.
Некоторые Maven-плагины требуют аналогов в
Gradle (например, nebula-release-plugin вместо maven-release-plugin).


#Java #middle #Gradle #Build_gradle
👍4
Зависимости и конфигурации в Gradle

Dependency Configurations

Конфигурации в Gradle определяют группы зависимостей, используемых для разных целей (компиляция, выполнение, тестирование). Они заменяют концепцию scope в Maven, предоставляя более гибкий подход.


Основные конфигурации

implementation:
Используется для зависимостей, необходимых для компиляции и выполнения кода проекта.
Не транзитивны для потребителей (в отличие от api).


Пример:
dependencies {
implementation 'org.springframework:spring-core:5.3.20'
}

Использование: Для внутренних зависимостей, которые не должны быть видны внешним модулям.


api:
Используется для зависимостей, которые становятся частью публичного API модуля и транзитивно передаются потребителям.
Применяется в основном в плагине java-library.


Пример:
plugins {
id 'java-library'
}
dependencies {
api 'org.apache.commons:commons-lang3:3.12.0'
}

Использование: Для библиотек, которые должны быть доступны в classpath потребителей (например, интерфейсы или DTO).


compileOnly:
Зависимости, необходимые только для компиляции, но не для выполнения.
Аналог provided в Maven.

Пример:
dependencies {
compileOnly 'javax.servlet:javax.servlet-api:4.0.1'
}

Использование: Для API, предоставляемых контейнером (например, Servlet API в веб-приложениях).


runtimeOnly:
Зависимости, необходимые только для выполнения, но не для компиляции.
Аналог runtime в Maven.


Пример:
dependencies {
runtimeOnly 'mysql:mysql-connector-java:8.0.28'
}

Использование: Для драйверов баз данных или библиотек, используемых только во время выполнения.


testImplementation:
Зависимости для компиляции и выполнения тестов.
Не транзитивны для основного кода.


Пример:
dependencies {
testImplementation 'junit:junit:4.13.2'
}

Использование: Для тестовых фреймворков и библиотек.


В памяти: Каждая конфигурация представлена как объект в модели Gradle, содержащий список зависимостей и их метаданные. Gradle хранит граф зависимостей в памяти как Directed Acyclic Graph (DAG), что увеличивает потребление памяти пропорционально количеству зависимостей и конфигураций.


Конфигурации в деталях: configurations {}
Gradle позволяет определять кастомные конфигурации через блок configurations для специфических нужд.

Пример:
configurations {
customConfig
}
dependencies {
customConfig 'com.example:library:1.0'
}
tasks.register('useCustomConfig') {
doLast {
configurations.customConfig.each { file ->
println "Using ${file.name}"
}
}
}

Назначение: Кастомные конфигурации позволяют группировать зависимости для нестандартных задач, таких как интеграционные тесты или обработка ресурсов.


Расширение конфигураций: Конфигурации могут наследовать друг от друга:
configurations {
customConfig.extendsFrom implementation
}

Это добавляет все зависимости implementation в customConfig.


В памяти: Кастомные конфигурации увеличивают объем графа зависимостей, так как Gradle создает дополнительные объекты для каждой конфигурации. Это требует больше памяти, особенно если конфигурации содержат много транзитивных зависимостей.


#Java #middle #Gradle #Configuration_gradle
👍3
Dependency Resolution

Gradle автоматически разрешает зависимости, загружая их из репозиториев (например, Maven Central) и управляя конфликтами версий.


Версионирование, конфликты, форсинг, exclusions

Версионирование:
Зависимости указываются с версией: group:artifact:version.
Поддерживаются динамические версии (например, 1.+) или диапазоны ([1.0,2.0)).


Пример:
dependencies {
implementation 'org.springframework:spring-core:5.+'
}


Конфликты:
Gradle использует стратегию newest-wins (новейшая версия побеждает) для разрешения конфликтов версий.
Пример: Если модуль A требует spring-core:5.3.20, а модуль B — spring-core:5.3.22,
Gradle выберет 5.3.22.

В памяти: Gradle строит граф зависимостей и разрешает конфликты во время фазы конфигурации, храня временные структуры для сравнения версий.


Форсинг:

Для принудительного использования конкретной версии используйте force:
configurations.all {
resolutionStrategy {
force 'org.springframework:spring-core:5.3.20'
}
}

В памяти: Форсинг добавляет правила в граф зависимостей, что минимально влияет на память, но требует дополнительных вычислений.


Exclusions:
Исключение транзитивных зависимостей для избежания конфликтов или ненужных библиотек:
dependencies {
implementation('org.springframework:spring-core:5.3.20') {
exclude group: 'commons-logging'
}
}


В памяти: Исключения уменьшают размер графа зависимостей, снижая потребление памяти и вероятность конфликтов.



BOM (Bill of Materials)

BOM — это файл, определяющий согласованные версии зависимостей, аналогично Maven. Gradle поддерживает BOM через платформы (platform).

Пример:
dependencies {
implementation platform('org.springframework.boot:spring-boot-dependencies:2.7.18')
implementation 'org.springframework.boot:spring-boot-starter'
}


Как работает:
BOM импортируется как платформа, предоставляя версии для всех зависимостей без необходимости их указания.
Gradle загружает BOM (POM-файл) из репозитория и применяет его версии к зависимостям.

В памяти: BOM увеличивает объем графа зависимостей, так как Gradle загружает и парсит дополнительный POM-файл. Однако это упрощает управление версиями, снижая вероятность конфликтов.



Модули и классы зависимостей

Модули: Gradle поддерживает зависимости от других Gradle-проектов (модулей) в многомодульных проектах:
dependencies {
implementation project(':module-core')
}


Модули добавляются в settings.gradle:include 'module-core', 'module-api'


Классы зависимостей: Gradle разрешает зависимости до уровня JAR-файлов, включаемых в classpath. Для Java-проектов это управляется плагином java или java-library.

В памяти: Зависимости от модулей добавляются в граф как узлы, увеличивая его размер. Gradle кэширует артефакты модулей в ~/.gradle/caches, снижая сетевые запросы, но требуя места на диске



Dependency Cache и Offline режим

Dependency Cache:
Gradle кэширует зависимости в ~/.gradle/caches/modules-2.
Кэш включает JAR-файлы, POM-файлы и метаданные, что минимизирует сетевые запросы.
Очистка кэша:rm -rf ~/.
gradle/caches

Offline режим:
Запустите Gradle с флагом --offline:./gradlew build --offline
Gradle использует только локальный кэш, что полезно для сборок без интернета.
Нюанс: Если зависимость отсутствует в кэше, сборка завершится с ошибкой.


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



#Java #middle #Gradle #Configuration_gradle
👍3
Lockfiles (Dependency Locking)

Lockfiles фиксируют точные версии зависимостей для воспроизводимости сборки.

Включение:
dependencyLocking {
lockAllConfigurations()
}


Генерация:
./gradlew dependencies --write-locks


Создает файлы gradle.lockfile в gradle/ для каждой конфигурации.

Пример lockfile:
org.springframework:spring-core:5.3.20
org.junit:junit:4.13.2

Использование: Gradle использует версии из lockfile, игнорируя динамические версии или новейшие доступные.


В памяти: Lockfiles загружаются как часть модели зависимостей, добавляя минимальный overhead. Они уменьшают время разрешения зависимостей, так как Gradle не проверяет удаленные репозитории.


Gradle Dependency Report (gradle dependencies)

Команда ./gradlew dependencies генерирует отчет о зависимостях для всех конфигураций:
./gradlew dependencies


Вывод (пример):
implementation - Implementation dependencies for the main source set.
\--- org.springframework:spring-core:5.3.20
\--- commons-logging:commons-logging:1.2
testImplementation - Implementation dependencies for the test source set.
\--- junit:junit:4.13.2


Флаги:
--configuration <name>: Для конкретной конфигурации, например, ./gradlew dependencies --configuration implementation.
-q: Для компактного вывода.


Использование: Анализ транзитивных зависимостей, выявление конфликтов.

В памяти: Gradle загружает полный граф зависимостей в память для генерации отчета, что может быть ресурсоемким для крупных проектов. Кэширование метаданных в ~/.gradle/caches ускоряет повторные вызовы.



Variant-aware Resolution

Gradle поддерживает вариантно-ориентированное разрешение зависимостей, что позволяет выбирать разные варианты артефакта в зависимости от атрибутов (например, версия Java, платформа).

Пример:
dependencies {
implementation 'org.example:library:1.0' {
attributes {
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 11)
}
}
}


Назначение:
Выбор артефакта для конкретной версии Java или платформы (например, Android vs JVM).
Поддержка мультиплатформенных библиотек (например, Kotlin Multiplatform).


В памяти: Gradle хранит атрибуты и варианты в графе зависимостей, что увеличивает сложность и потребление памяти, особенно для библиотек с множеством вариантов.


#Java #middle #Gradle #Configuration_gradle
👍3
Задачи и жизненный цикл в Gradle


Task API: Task, DefaultTask, @TaskAction

Задачи (tasks) — это основная единица работы в Gradle, представляющая такие действия, как компиляция, тестирование или упаковка. Task API предоставляет инструменты для создания и настройки задач.


Основные компоненты

Task:
Интерфейс org.gradle.api.Task, определяющий базовую функциональность задачи (например, выполнение, зависимости).
Все задачи в
Gradle реализуют этот интерфейс.

DefaultTask:
Класс org.gradle.api.DefaultTask, стандартная реализация интерфейса Task.
Используется для создания пользовательских задач.


Пример (Groovy DSL):
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction

class CustomTask extends DefaultTask {
@TaskAction
void executeTask() {
println 'Executing custom task'
}
}

tasks.register('customTask', CustomTask)


@TaskAction:
Аннотация, указывающая метод, который выполняется при запуске задачи.

Пример (Kotlin DSL):
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction

open class CustomTask : DefaultTask() {
@TaskAction
fun executeTask() {
println("Executing custom task")
}
}

tasks.register<CustomTask>("customTask")


В памяти: Каждая задача представлена как объект в JVM, содержащий метаданные (имя, зависимости, действия). Gradle загружает все задачи в память во время фазы конфигурации, что увеличивает потребление памяти пропорционально их количеству. Плагины, такие как java, добавляют множество задач (например, compileJava, test), увеличивая overhead.


Gradle Lifecycle

Жизненный цикл Gradle состоит из трех фаз: Initialization, Configuration и Execution. Каждая фаза выполняет определенные функции и влияет на производительность и память.

Initialization Phase:
Gradle загружает settings.gradle для определения структуры проекта (корневое имя, подмодули).
Создает объекты Project для корневого проекта и подпроектов.
Устанавливает начальные настройки, такие как репозитории и плагины.

В памяти: Минимальная фаза по потреблению ресурсов, так как загружается только settings.gradle и связанные плагины. Объем памяти зависит от количества модулей (обычно 50-100 МБ).


Configuration Phase:

Gradle парсит все файлы build.gradle, создавая модель проекта и граф задач (Directed Acyclic Graph, DAG).
Все скрипты конфигурации выполняются, даже для задач, которые не будут запущены.
Пример: Определение зависимостей, задач и плагинов.

В памяти: Самая ресурсоемкая фаза, так как Gradle загружает и компилирует все скрипты, плагины и зависимости. Для крупных проектов может потребоваться 500-1000 МБ памяти.

Оптимизация: Используйте флаг --configure-on-demand для конфигурации только необходимых модулей:
./gradlew build --configure-on-demand


Execution Phase:
Gradle выполняет задачи, указанные в командной строке (например, ./gradlew build), в порядке, определенном DAG.
Инкрементальность пропускает задачи, чьи входные/выходные данные не изменились (см. ниже).

В памяти: Зависит от сложности задач. Например, compileJava загружает исходные файлы и зависимости, а test — тестовые классы и фреймворки. Параллельное выполнение (--parallel) увеличивает пиковое потребление памяти.


Нюансы:

Конфигурация выполняется всегда, что замедляет сборку, особенно для крупных проектов.
Gradle Daemon сохраняет JVM между сборками, ускоряя повторные запуски, но увеличивая базовое потребление памяти (200-300 МБ).
Используйте --no-daemon для одноразовых сборок:

./gradlew build --no-daemon


#Java #middle #Gradle #Task #Lifecycle
👍2
Task Graph, зависимости между задачами

Gradle строит Directed Acyclic Graph (DAG) для задач, где узлы — задачи, а ребра — зависимости. Это определяет порядок выполнения.

Зависимости между задачами

dependsOn:
Указывает, что задача зависит от выполнения других задач.

Пример:
task compileJava {
doLast { println 'Compiling Java' }
}
task test(dependsOn: compileJava) {
doLast { println 'Running tests' }
}

Gradle выполнит compileJava перед test.


mustRunAfter:
Определяет порядок выполнения без строгой зависимости.

Пример:

task taskA {
doLast { println 'Task A' }
}
task taskB {
mustRunAfter 'taskA'
doLast { println 'Task B' }
}

Если обе задачи выполняются, taskB будет после taskA, но taskB может выполняться отдельно.


finalizedBy:
Указывает задачу, которая выполняется после завершения текущей, даже при ошибке.

Пример:
task build {
doLast { println 'Building' }
}
task cleanUp {
doLast { println 'Cleaning up' }
}
build.finalizedBy cleanUp


В памяти: DAG задач хранится как структура данных в JVM, где каждая задача — объект с метаданными (зависимости, действия). Размер графа пропорционален количеству задач, что может увеличить потребление памяти до нескольких сотен МБ в крупных проектах.



Incremental Build и Up-to-Date Checks

Gradle оптимизирует производительность за счет инкрементальной сборки, пропуская задачи, чьи входные/выходные данные не изменились.

Механизм:
Gradle проверяет хэши входных (исходные файлы, свойства) и выходных данных (скомпилированные классы, JAR).
Если хэши совпадают, задача помечается как up-to-date и пропускается.


Пример вывода:
> Task :compileJava UP-TO-DATE


Пример настройки:
tasks.named('compileJava') {
inputs.files('src/main/java')
outputs.dir('build/classes/java/main')
}


В памяти: Gradle хранит хэши входов/выходов в памяти и в ~/.gradle/caches для сравнения. Это добавляет небольшой overhead (около 10-50 МБ), но значительно ускоряет сборку.


Нюансы:

Неправильная настройка входов/выходов может привести к ненужному выполнению задач.
Используйте --info для анализа, почему задача не была пропущена:

./gradlew build --info



Gradle Inputs/Outputs (Task Inputs/Outputs)

Задачи Gradle имеют входы и выходы, которые определяют, что влияет на выполнение задачи и что она производит.

Inputs:
Файлы, свойства или другие данные, от которых зависит задача.

Пример:
task processFiles {
inputs.files fileTree('src/main/resources')
doLast {
println 'Processing files'
}
}


Outputs:
Файлы или директории, создаваемые задачей.

Пример:
task generateReport {
outputs.file file('build/report.txt')
doLast {
file('build/report.txt').text = 'Report content'
}
}


В памяти: Gradle хранит метаданные входов/выходов в памяти и кэширует хэши в ~/.gradle/caches. Для задач с большим количеством файлов (например, compileJava) это увеличивает потребление памяти, так как Gradle сканирует файловую систему.


Нюансы:
Явно указывайте входы/выходы для кастомных задач, чтобы включить инкрементальность.

Используйте inputs.property для не-файловых входов:
task customTask {
inputs.property 'version', project.version
doLast { println "Version: ${project.version}" }
}



#Java #middle #Gradle #Task #Lifecycle
👍1