Avatar ·

Как убрать plain.jar в Spring Boot 2.5+ при сборке Gradle (Kotlin DSL)?

Привет! Я использую Spring Boot 2.5.0 с Gradle (Kotlin DSL) и заметил, что при сборке проекта генерируется два jar-файла: `my-app-0.0.1-SNAPSHOT.jar` (рабочий, исполняемый) и `my-app-0.0.1-SNAPSHOT-plain.jar`. Последний, как я понял, содержит только классы без зависимостей и не запускается. Он занимает место и путается в CI/CD пайплайне. Я хочу от него избавиться. Мой `build.gradle.kts` выглядит так: ```kotlin plugins { id("org.springframework.boot") version "2.5.0" id("io.spring.dependency-management") version "1.0.11.RELEASE" kotlin("jvm") version "1.5.10" kotlin("plugin.spring") version "1.5.10" } java.sourceCompatibility = JavaVersion.VERSION_11 dependencies { implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") testImplementation("org.springframework.boot:spring-boot-starter-test") } tasks.withType { kotlinOptions { freeCompilerArgs = listOf("-Xjsr305=strict") jvmTarget = "11" } } ``` Я слышал, что это изменение связано с версией 2.5.0. Можно ли полностью отключить генерацию `plain.jar`? Или это нужно для чего-то полезного? Подскажите, как правильно настроить сборку. Заранее спасибо! <<>>

Причина появления plain.jar

Начиная с Spring Boot 2.5.0, плагин org.springframework.boot начал генерировать два артефакта:

  • Исполняемый jar (fat jar) — содержит все зависимости, запускается через java -jar. Именно его вы используете в продакшене.
  • Plain jar — это оригинальный jar без встроенных библиотек. Он создаётся для обратной совместимости (например, если другой проект использует ваш модуль как библиотеку).
Это изменение было внесено, чтобы разделить два разных сценария: запуск приложения и использование как библиотеки.

Как отключить генерацию plain.jar

Если ваш проект — это финальное приложение (микросервис, веб-сервер) и вы не планируете, чтобы другие проекты подключали его как зависимость, plain.jar вам не нужен. Отключить его можно двумя способами.

Способ 1: Через конфигурацию плагина (рекомендуется)

Добавьте в build.gradle.kts следующий блок:

import org.springframework.boot.gradle.tasks.bundling.BootJar

tasks.withType<BootJar> {
    // Отключаем создание plain.jar
    this.archiveFileName.set("${project.name}-${project.version}.jar")
}

tasks.withType<Jar> {
    // Полностью отключаем обычный Jar (plain)
    enabled = false
}

Полный файл будет выглядеть так:

plugins {
    id("org.springframework.boot") version "2.5.0"
    id("io.spring.dependency-management") version "1.0.11.RELEASE"
    kotlin("jvm") version "1.5.10"
    kotlin("plugin.spring") version "1.5.10"
}

java.sourceCompatibility = JavaVersion.VERSION_11

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs = listOf("-Xjsr305=strict")
        jvmTarget = "11"
    }
}

// Блок отключения plain.jar
tasks.withType<BootJar> {
    this.archiveFileName.set("${project.name}-${project.version}.jar")
}

tasks.withType<Jar> {
    enabled = false
}

Способ 2: Через Gradle API (более лаконичный)

Если вы используете Gradle 7+, можно просто сказать, что обычный Jar не нужен:

tasks.named<Jar>("jar") {
    enabled = false
}

Этот метод короче, но менее явный — он скрывает задачу jar, но BootJar продолжает работать.

Проверка результата

После добавления любого из этих блоков выполните команду:

./gradlew clean bootJar

В папке build/libs останется только один файл — my-app-0.0.1-SNAPSHOT.jar. Plain.jar больше не создаётся.

Важное замечание

Если в будущем вы решите, что ваш модуль должен использоваться как библиотека в другом Spring Boot проекте, верните enabled = true для Jar. Plain.jar содержит только ваши классы и ресурсы без зависимостей, что необходимо для корректного dependency management.

<<>>

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

Если вы не хотите редактировать конфигурацию плагина (например, из-за строгих правил в проекте), можно просто удалять plain.jar после сборки через clean или добавить шаг в CI/CD:

tasks.named("bootJar") {
    doLast {
        val plainJar = file("build/libs/${project.name}-${project.version}-plain.jar")
        if (plainJar.exists()) {
            plainJar.delete()
            println("Plain jar deleted: ${plainJar.name}")
        }
    }
}

Этот код выполняется после успешной сборки BootJar и удаляет лишний файл. Минус — файл всё равно создаётся на короткое время, что может быть проблемой при больших проектах.

Почему это может быть полезно?

  • Не требует изменения логики плагина Spring Boot.
  • Легко внедрить в существующий проект без риска сломать сборку.
  • Можно комбинировать с условиями (например, удалять только в production-сборках).

Однако рекомендую использовать первый способ (отключение через enabled = false) — он чище и не создаёт мусора.