spring-projects-experimental / spring-boot-thin-launcher

Tools for building "thin" executable jars, with a focus on, but not exclusively for, Spring Boot
https://github.com/dsyer/spring-boot-thin-launcher
Apache License 2.0
681 stars 90 forks source link

Write a thin jar into a shell script, then run it failed! #199

Closed xunyao4dev closed 1 year ago

xunyao4dev commented 1 year ago

build.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '2.7.12'
    id 'io.spring.dependency-management' version '1.0.15.RELEASE'
    id 'maven-publish'
    id 'org.springframework.boot.experimental.thin-launcher' version '1.0.30.RELEASE'
}

group = 'cn.abc'
version = '0.0.1'
sourceCompatibility = '11'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
    all*.exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
}

repositories {
    maven { url "https://abc.cn/repository/maven-public/" }
}

publishing {
    publications {
        maven(MavenPublication) {
            from components.java
        }
    }
}

ext {
    set('springShellVersion', "2.1.10")
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.shell:spring-shell-starter'
    implementation 'mysql:mysql-connector-java:8.0.33'
    implementation 'com.google.protobuf:protobuf-java:3.22.2'
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'
    implementation 'org.springframework.boot:spring-boot-starter-log4j2'
    implementation 'org.apache.commons:commons-collections4:4.4'
    implementation 'org.apache.commons:commons-lang3'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.shell:spring-shell-dependencies:${springShellVersion}"
    }
}

task release() {
    dependsOn thinJar
    // command like: cat a.txt b.txt > c.txt
    def commands = [
            "cat $rootDir/script/init.sh $buildDir/libs/tqa-tool-0.0.1.jar > $buildDir/tqa-tool.sh",
            "chmod +x $buildDir/tqa-tool.sh"
    ]

    doLast {
        exec {
            executable 'bash'
            args '-c', commands.join(" && ")
        }
    }
}

script/init.sh

#!/bin/sh

export JAVA_HOME=/usr/java/jdk-11.0.15

MYSELF=`which "$0" 2>/dev/null`
[ $? -gt 0 -a -f "$0" ] && MYSELF="./$0"

java="$JAVA_HOME/bin/java"
java_args="-Dthin.debug=true"

exec "$java" $java_args -jar $MYSELF "$@"
exit 1 

after execute ./gradlew clean release, I got a shell script named tqa-tool.sh which include the thin jar, but when I execute this script in the server, a error occurred, below:

Exception in thread "main" java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.springframework.boot.loader.wrapper.ThinJarWrapper.launch(ThinJarWrapper.java:139)
        at org.springframework.boot.loader.wrapper.ThinJarWrapper.main(ThinJarWrapper.java:107)
Caused by: java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
        at org.springframework.boot.loader.thin.ThinJarLauncher.launch(ThinJarLauncher.java:221)
        at org.springframework.boot.loader.thin.ThinJarLauncher.main(ThinJarLauncher.java:168)
        ... 6 more
Caused by: java.lang.NoClassDefFoundError: org/springframework/boot/SpringApplication
        at cn.thinkingdata.ta.tool.TaToolApplication.main(TaToolApplication.java:12)
        ... 15 more
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication
        at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:476)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)
        at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151)
        at org.springframework.boot.loader.thin.ThinJarLauncher$ThinJarClassLoader.loadClass(ThinJarLauncher.java:530)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
        ... 16 more
xunyao4dev commented 1 year ago

@dsyer Hello, Dsyer, Could you give me a hand? Thanks so much.

dsyer commented 1 year ago

It works for me. Maybe you compiled with a different JDK than the one you use in the script?

dsyer commented 1 year ago

UPDATE: I see the same failure with a JAR file built by Gradle. It works with a Maven project. Not sure why, but I will look into it.

dsyer commented 1 year ago

I see the issue: the Gradle-generated JAR file has META-INF/maven/org.springframework.boot.experimental/spring-boot-thin-wrapper/pom.xml in it, and the one from Maven does not. This extra pom.xml confuses the ThinJarLauncher when it is looking for dependencies. It doesn't get confused when you launch from a JAR file with the conventional name starting with the artifactId. So you could fix your script just by calling it tqa-tool.jar or just tqa-tool.

dsyer commented 1 year ago

Should be fixed in fe46eee. The workaround would still work,