Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
562 views
in Technique[技术] by (71.8m points)

spring boot - Exception in thread "main" java.lang.ClassNotFoundException - Springboot, multimodule gradle project

I know this is a common issue and I'm embarrassed to be asking it but I can't work out why I cant load the main class of my multimodule Springboot app.

Full stacktrace:

Exception in thread "main" java.lang.ClassNotFoundException: space.forloop.addon.app.Main
    at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)
    at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    at java.base/java.lang.Class.forName0(Native Method)
    at java.base/java.lang.Class.forName(Class.java:398)
    at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:46)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:107)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)

A have a root-level gradle.build file

plugins {
    id 'org.springframework.boot' version '2.4.1'
    id 'io.spring.dependency-management' version '1.0.10.RELEASE'
    id 'java'
}

repositories {
    mavenCentral()
}

bootJar {
    mainClass = 'space.forloop.addon.app.Main'
}

def javaProjects = [
        'addon-sync-app',
        // Removed, not important
]

javaProjects.each {
    name ->

        project(":$name") {
            apply plugin: 'org.springframework.boot'
            apply plugin: 'io.spring.dependency-management'
            apply plugin: 'java'

            repositories {
             // Removed, not important
            }

            dependencies {
             // Removed, not important
            }
        }
}

In the package module addon-sync-app I have another build.gradle file which just has:

apply plugin: 'org.springframework.boot'

dependencies {
   // Removed, not important
}

Looking at the documentation of Configuring the Main Class I was sure adding:

bootJar {
    mainClass = 'space.forloop.addon.app.Main'
}

To the root gradle.build file was the correct thing here, but seems not. Any thing else I might have missed?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You are using the Spring Boot plugin in the wrong way. It's such a common mistake that I think they need to document it better or just make it work out-of-the-box. Oh well.

In a Gradle multi-project, you typically define your support libraries and then one or more runnable or deployable applications.

One thing I can't tell from your description is whether you intend the root project to build that final application, or if it should rather be the addon-sync-app project. Given the name, I am assuming the latter, but it can be either one (but generally not both at the same time).

When you apply the Spring Boot plugin to a project (and it doesn't matter if it is the root project or a sub-project), and you rely on defaults, it will take that project and make it into a "fat jar", which requires a special classloader to run. This makes it unsuitable as a normal library. So when you try to depend on it in a normal way, your classes will not be found.

To fix it, you should only apply the Spring Boot plugin to the project that builds the final application jar. If that is addon-sync-app, then remove it from the root and all non-application sub-projects.

If instead, you want the root project to produce the final application, you need to create dependencies to all the required sub-projects and, just as before, remove the Spring Boot plugin from them as well.

One thing you lose when not applying the Spring Boot plugin is the automatic dependency to the BOM which defines default versions of dependencies. If you like to keep using that without creating fat jars of your libraries, there are a few different ways to handle that. I wrote a (little bit too long) answer on that here.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...