spring-projects / spring-boot

Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.
https://spring.io/projects/spring-boot
Apache License 2.0
75.09k stars 40.67k forks source link

Spring Boot Jar cannot find auto config files - bug #42029

Closed dreamstar-enterprises closed 2 months ago

dreamstar-enterprises commented 2 months ago

I have a fairly simple Spring Boot app. One yaml file with spring gateway configurations, and then one file with the main Application class and the main function.

I build the jar file as follows:

./gradlew clean bootJar -x test

It gets built without problems.

The build.gradle.kts file looks like this:

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

plugins {
    id("org.springframework.boot") version "3.3.2"
    id("io.spring.dependency-management") version "1.1.6"
    kotlin("jvm") version "1.9.24"
    kotlin("plugin.spring") version "1.9.24"
    application
}

application {
    mainClass.set("com.example.reverseproxy.ReverseProxyApplicationKt")
}

group = "com.example"
version = "0.0.1-SNAPSHOT"

java {
    sourceCompatibility = JavaVersion.VERSION_17
}

configurations {
    compileOnly {
        extendsFrom(configurations.annotationProcessor.get())
    }
}

repositories {
    mavenCentral()
}

extra["springCloudVersion"] = "2023.0.3"

dependencies {
    /* kotlin co-routines */
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")

    /* kotlin reflection */
    implementation("org.jetbrains.kotlin:kotlin-reflect")

    /* spring web */
//    implementation("org.springframework.boot:spring-boot-starter-webflux")

    /* spring cloud gateway */
    implementation("org.springframework.cloud:spring-cloud-starter-gateway")
    implementation("org.springframework.boot:spring-boot-starter-actuator")

    /* test - dependencies */
    testImplementation("org.springframework.boot:spring-boot-starter-test")
    testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")

//    testImplementation("io.projectreactor:reactor-test")
//    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
//    implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
    implementation(kotlin("stdlib-jdk8"))

}

dependencyManagement {
    imports {
        mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("springCloudVersion")}")
    }
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs += "-Xjsr305=strict"
        jvmTarget = "17"
    }
}

tasks.withType<Test> {
    enabled = false
    useJUnitPlatform()
}

tasks.withType<Jar> {

    duplicatesStrategy = DuplicatesStrategy.EXCLUDE

    manifest {
        attributes["Main-Class"] = "com.example.reverseproxy.ReverseProxyApplicationKt"
    }

    archiveBaseName.set("ReverseProxy")
    archiveVersion.set("0.0.1-SNAPSHOT")

    from(sourceSets.main.get().output)

    // Include dependencies in the JAR file
    dependsOn(configurations.runtimeClasspath)
    from({
        configurations.runtimeClasspath.get()
            .filter { it.name.endsWith("jar") }
            .map { zipTree(it) }
    })

    // exclude specific signed files from being included in the final JAR
    exclude("META-INF/*.SF")
    exclude("META-INF/*.DSA")
    exclude("META-INF/*.RSA")
}

tasks.named("bootJar") {
    dependsOn("jar")
}
tasks.named("bootJar") {
    mustRunAfter("jar")
}
tasks.named("bootDistZip") {
    dependsOn("jar")
}
tasks.named("bootDistZip") {
    mustRunAfter("jar")
}
tasks.named("bootDistTar") {
    dependsOn("jar")
}
tasks.named("bootDistTar") {
    mustRunAfter("jar")
}
tasks.named("startScripts") {
    dependsOn("bootJar")
}
tasks.named("startScripts") {
    mustRunAfter("bootJar")
}

However, when I run this

java -jar build/libs/ReverseProxy-0.0.1-SNAPSHOT.jar

I keep getting:

19:35:51.003 [main] WARN org.springframework.context.annotation.AnnotationConfigApplicationContext -- Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'httpClientSslConfigurer' defined in class path resource [org/springframework/cloud/gateway/config/GatewayAutoConfiguration$NettyConfiguration.class]: Unsatisfied dependency expressed through method 'httpClientSslConfigurer' parameter 0: No qualifying bean of type 'org.springframework.boot.autoconfigure.web.ServerProperties' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
19:35:51.006 [main] ERROR org.springframework.boot.SpringApplication -- Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'httpClientSslConfigurer' defined in class path resource [org/springframework/cloud/gateway/config/GatewayAutoConfiguration$NettyConfiguration.class]: Unsatisfied dependency expressed through method 'httpClientSslConfigurer' parameter 0: No qualifying bean of type 'org.springframework.boot.autoconfigure.web.ServerProperties' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

enter image description here

I'm not really sure where I am going wrong?

Can someone help?

UPDATE

The below did not help. Any ideas?

// ensure that both compiled classes and resources are included in the JAR file
from(sourceSets.main.get().output)
sourceSets.main.configure {
    resources.srcDirs("src/main").includes.addAll(arrayOf("**/*.*"))
}

UPDATE 2

If I comment this out from the gradle file,

implementation("org.springframework.cloud:spring-cloud-starter-gateway")

It works. Only problem is that since this is a reverse proxy, its a dependency I very much need.

philwebb commented 2 months ago

I see you have also posted this question on stackoverflow.com. It's always advisable to mention if you've cross-posted somewhere so folks don't end up duplicating effort to help you.

I think stackoverflow.com is probably the best place to get help unless we can determine that this is a bug in Spring Boot.

dreamstar-enterprises commented 2 months ago

Hi Phil, Thanks for replying. The reason for posting here as well, is because I do think this is a bug, and so worth bringing to attention to the dev team.

There aren't many lines of code:

Literally, just this in my yaml

## spring settings
spring:
  # profile settings
  profiles:
    active: ssl
  # cloud gateway settings
  cloud:
    gateway:
      default-filters:
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
      routes:
        # SPAs assets
        - id: angular-ui
          uri: ${angular-server-uri}
          predicates:
            - Path=${angular-prefix}/**

        # BFF-server
        - id: bff
          uri: ${bff-server-uri}
          predicates:
            - Path=${bff-prefix}/**
          filters:
            - StripPrefix=1

And then this kotlin class

@SpringBootApplication
class ReverseProxyApplication

    fun main(args: Array<String>) {
        runApplication<ReverseProxyApplication>(*args)

}

Removing this from my gradle file makes the problem when running bootJar go away. But naturally its a dependency I need for a simple reverse proxy (or any app that uses spring cloud gateway).

implementation("org.springframework.cloud:spring-cloud-starter-gateway")

Is anyone able to replicate to the same error?

image

Repo (Minimum Reproducable example):

https://github.com/dreamstar-enterprises/docs/tree/master/Spring%20BFF/ReverseProxy

philwebb commented 2 months ago

The reason for posting here as well, is because I do think this is a bug, and so worth bringing to attention to the dev team.

That's understandable, but please provide a reference to the stackoverflow.com question so that we know it exists.

I don't think this is a bug, it looks like a misconfiguration of your build.gradle.kts file. I've edited by previous answer with a fix.

dreamstar-enterprises commented 2 months ago

Hi Phil,

Thanks for solving it, and being so helpful.

I wondered. Do you do consultancy work? I'm struggling with a handlful of issues with a Spring BFF I'm trying to implement. (it uses Spring Cloud Gateway and Spring OAuthClient), mainly for storing session data to redis, and relaying tokens.

Would be grateful if you could let me know. I can email you more on the details.

philwebb commented 2 months ago

Sorry, the open source work consumes almost all my time so I don't do consulting. But thanks for the kind words.