【问题标题】:Building an executable jar that can be published to maven local repo with `publishToMavenLocal` - spring boot project使用 `publishToMavenLocal` 构建可以发布到 maven 本地 repo 的可执行 jar - spring boot 项目
【发布时间】:2020-08-09 10:07:18
【问题描述】:

在构建可执行 jar(可以使用 java -jar app.jar 运行)方面需要帮助,该 jar 可以发布到 Spring Boot 项目的 maven 本地存储库(使用 gradle publishToMavenLocal)。

使用这些 gradle 设置 gradle publishToMavenLocal 有效。

Gradle 版本是 6.3 Spring Boot 版本为 2.2.6 Kotlin 1.3.71

父母build.gradle.kts

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

buildscript {
    repositories {
        mavenLocal()
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.2.6.RELEASE")
    }
}

plugins {
    id("org.springframework.boot") version "2.2.6.RELEASE" apply false
    id("io.spring.dependency-management") version "1.0.9.RELEASE" apply false
    kotlin("jvm") version "1.3.71" apply false
    kotlin("plugin.spring") version "1.3.71" apply false
    `maven-publish`
    `java-library`
    signing
}

allprojects {
    group = "com.example.user"
    version = "0.0.1-SNAPSHOT"

    tasks.withType<JavaCompile> {
        sourceCompatibility = "1.8"
        targetCompatibility = "1.8"
    }

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

subprojects {
    repositories {
        mavenLocal()
        mavenCentral()
    }

    apply {
        plugin("io.spring.dependency-management")
        plugin("maven-publish")
    }
}

子项目build.gradle.kts:

plugins {
    id("org.springframework.boot")
    id("io.spring.dependency-management")
    kotlin("jvm")
    kotlin("plugin.spring")
}


val developmentOnly by configurations.creating
configurations {
    runtimeClasspath {
        extendsFrom(developmentOnly)
    }
}

dependencies {
    implementation(project(":common"))
    implementation(project(":user-models"))
    implementation(project(":user-core"))
    implementation("org.springframework.boot:spring-boot-starter-webflux") {
        exclude(group = "org.springframework.boot", module = "spring-boot-starter-logging")
    }

    implementation("org.springframework.boot:spring-boot-maven-plugin:2.2.6.RELEASE")


    implementation(group = "org.springframework.boot", name = "spring-boot-autoconfigure", version = "2.2.6.RELEASE")
    implementation(group = "org.springframework.boot", name = "spring-boot-starter-parent", version = "2.2.6.RELEASE")

    implementation("org.springframework.boot:spring-boot-configuration-processor:2.2.6.RELEASE")

    implementation("org.projectreactor:reactor-spring:1.0.1.RELEASE")
    implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")


    implementation(group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version = "1.3.5")
    implementation(group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-reactor", version = "1.3.5")
    implementation(group = "org.springframework.boot", name = "spring-boot-starter-log4j2", version = "2.2.6.RELEASE")

    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")

    developmentOnly("org.springframework.boot:spring-boot-devtools")

    testImplementation("org.springframework.boot:spring-boot-starter-test") {
        exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
    }

}

tasks.withType<Test> {
    useJUnitPlatform()
}

tasks.jar {
    enabled = true
    manifest {
        attributes["Main-Class"] = "com.subnub.user.service.ServiceApplicationKt"
        attributes["Class-Path"] = configurations.compileClasspath.get().map { it.name }.joinToString(" ")
    }

    from(configurations.compileClasspath.get().map { if(it.isDirectory) it else zipTree(it) })

    duplicatesStrategy = DuplicatesStrategy.INCLUDE

}

tasks.bootJar {
    enabled = false
    archiveClassifier.set("application")
    mainClassName = "com.example.user.service.ServiceApplicationKt"
}


publishing {
    publications {
        create<MavenPublication>("mavenJava") {
            from(components["java"])

            afterEvaluate {
                artifactId = tasks.jar.get().archiveBaseName.get()
            }
        }
    }
}

但是使用这些 gradle 设置构建的 jar 在尝试运行时会中断

标准错误:

➜  example-user git:(master) ✗     java -jar example-service/build/libs/example-service-0.0.1-SNAPSHOT.jar
[INFO ] 2020-04-25 22:18:11.871 [main] ServiceApplicationKt - Starting ServiceApplicationKt on admins-mbp-7 with PID 4663 (/Users/zerocase/personal/startups/example/code/example-user/example-service/build/libs/example-service-0.0.1-SNAPSHOT.jar started by abhishek in /Users/zerocase/personal/startups/example/code/example-user)
[INFO ] 2020-04-25 22:18:11.874 [main] ServiceApplicationKt - No active profile set, falling back to default profiles: default
[ERROR] 2020-04-25 22:18:12.055 [main] SpringApplication - Application run failed
java.lang.IllegalArgumentException: No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.
        at org.springframework.util.Assert.notEmpty(Assert.java:464) ~[example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.getCandidateConfigurations(AutoConfigurationImportSelector.java:173) ~[example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.getAutoConfigurationEntry(AutoConfigurationImportSelector.java:116) ~[example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector$AutoConfigurationGroup.process(AutoConfigurationImportSelector.java:396) ~[example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGrouping.getImports(ConfigurationClassParser.java:878) ~[example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.processGroupImports(ConfigurationClassParser.java:808) ~[example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorHandler.process(ConfigurationClassParser.java:779) ~[example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:192) ~[example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:319) ~[example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:236) ~[example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:275) ~[example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:95) ~[example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706) ~[example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532) ~[example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66) ~[example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) [example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [example-service-0.0.1-SNAPSHOT.jar:?]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) [example-service-0.0.1-SNAPSHOT.jar:?]
        at com.example.user.service.ServiceApplicationKt.main(ServiceApplication.kt:19) [example-service-0.0.1-SNAPSHOT.jar:?]

我已经尝试了此处建议的解决方法 (https://docs.gradle.org/current/userguide/upgrading_version_6.html#publishing_spring_boot_applications) 来发布 bootJar 工件。在这种情况下,jar 可以正常工作,但是,

configurations {
    listOf(apiElements, runtimeElements).forEach {
        it.get().outgoing.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(tasks.jar) }
        it.get().outgoing.artifact(tasks.bootJar)
    }
}

但是 gradle 不允许我这样做 gradle pTML

➜  example-user git:(master) ✗ gradle pTML
> Task :user-service:publishMavenJavaPublicationToMavenLocal FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':user-service:publishMavenJavaPublicationToMavenLocal'.
> Failed to publish publication 'mavenJava' to repository 'mavenLocal'
   > Artifact example-service-0.0.1-SNAPSHOT.jar wasn't produced by this build.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 1s
16 actionable tasks: 3 executed, 13 up-to-date

【问题讨论】:

    标签: spring-boot kotlin gradle jar


    【解决方案1】:

    解决了问题,artifact 需要在发布范围内定义。

    publishing {
        publications {
            create<MavenPublication>("mavenJava") {
                //from(components["java"]) // <-- this is not required
                artifact(tasks.bootJar.get()) // <-- this is required
            }
        }
    }
    

    并对configurations 范围(ref)稍作修改:

    configurations {
        listOf(apiElements, runtimeElements).forEach {
            // Method #1
            val jar by tasks
            it.get().outgoing.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(jar) }
    
            // Method #2
            it.get().outgoing.artifact(tasks.bootJar)
        }
    }
    

    这里是一些发布出版物的示例implementations

    【讨论】:

      【解决方案2】:

      我修复了错误Artifact ....jar wasn't produced by this build 添加参数enabled = truejar 任务

      jar {
         enabled = true
      }
      

      【讨论】:

        猜你喜欢
        • 2019-05-19
        • 1970-01-01
        • 1970-01-01
        • 2017-11-21
        • 1970-01-01
        • 2014-12-18
        • 2010-12-21
        • 1970-01-01
        相关资源
        最近更新 更多