SpringBoot与多项目Gradle --> 主类名未配置且无法解析

10

我有以下的项目结构:

RootProject
├── lib
     └── src
          └── main
               └── java
                    └── ...
├── test-project
     └── src
          └── main
               └── java
                    └── ...

└── build.gradle

我正在尝试遵循Gradle最佳实践来进行多项目构建,因此我将整个构建过程描述在单个build.gradle文件中。

"RootProject"只是一个没有任何代码的根项目,其唯一目的是为其子项目:"lib"和"test-project"提供单个build.gradle文件。

"test-project"是一个SpringBoot项目(微服务),使用"lib"作为编译依赖项。

我的通用build.gradle如下所示:

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


allprojects {
    repositories {
        jcenter()
    }
}


subprojects {

    apply plugin: 'io.spring.dependency-management'
    apply plugin: 'org.springframework.boot'

    group = 'com.xxx.yyy'
    version = '1.0'

    sourceCompatibility = 1.8
    targetCompatibility = 1.8
}


project(":lib"){

    apply plugin: 'java-library'

    dependencies {

        implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web'
        implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa'
        testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-test'
    }

    bootJar { enabled = false }
    jar { enabled = true }
}

project(":test-project"){

    apply plugin: 'java'

    dependencies {
        implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web'
        implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa'
        implementation project(":lib")
        implementation ('mysql:mysql-connector-java')
    }
}

“lib”和“test-project”都已成功构建。但是,当我尝试在根项目上执行“bootJar”任务(这应该会触发所有子项目上的“build”任务)时,我遇到了以下错误:

Main class name has not been configured and it could not be resolved

有任何想法吗?


如果主类在您的lib项目中,而spring-boot插件在test-project中,则需要在插件中配置主类。还要确保:主类上有@SpringBoot应用程序注释? - wemu
1个回答

21

多项目构建最佳实践简介

当你说:

我试图遵循 Gradle 的多项目构建最佳实践,因此我在单个 build.gradle 文件中描述整个构建过程。

我认为这并不是一个好的实践,并且这也不是指南中真正推荐的做法。

在指南简介中:

虽然每个子项目可以完全独立地进行配置,但子项目共享共同的特点是很常见的。因此,通常最好在项目之间共享配置,使相同的配置影响多个子项目。

=> 确实,子项目之间共享的共同特点应该在根项目构建的中心位置进行配置。

在指南的后面(在 此部分)有一个示例,其中在根项目脚本中定义了子项目特定的配置,但在示例描述中有一个注释:

所有构建逻辑都在根项目的构建脚本中。(2)

(2):我们在这里这样做是为了使布局更加简单。 我们通常将项目特定的内容放入各自项目的构建脚本中。

关于你的问题

我假设你的 lib 项目是一个纯“简单”的 Java lib 项目(没有 Spring 或 SpringBoot 依赖项),而 test-project 是包含 SpringBoot 应用程序类(特别是 @SpringBootApplication 主应用程序类)的项目。 按照上述最佳实践,您应该拥有三个不同的项目构建脚本:

  • 根项目:用于定义在子项目中共享的通用配置(Java 插件配置、存储库、共享依赖项等)
  • lib 项目:此 lib 项目的特定配置(Java-library 插件、特定依赖项等)
    • 没有理由将 spring-boot 插件应用于此子项目,这实际上是导致错误“找不到主类”的原因
    • 如果这个项目依赖于 Spring-core 模块,则可以简单地应用 io.spring.dependency-management 插件(在这种情况下,在根项目构建中应用此依赖关系插件,以在两个子项目中使用相同的 Spring 版本是有意义的)
  • test-project 项目:与 Spring Boot 应用程序相关的配置(SpringBoot 插件和依赖项)

示例

根项目构建

ext{
    slf4jVersion = "1.7.25"
}

subprojects {
    apply plugin: "java"
    // if both subprojects share some Spring related dependencies, apply the Spring `io.spring.dependency-management` here.

    group = 'com.xxx.yyy'
    version = '1.0'

    sourceCompatibility = 1.8
    targetCompatibility = 1.8

    repositories {
        jcenter()
    }
}

'lib' 项目构建

plugins{
    id 'java-library'
}

dependencies {
    implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion
    // lib dependencies
}

'test-project'构建

plugins {     
    id "org.springframework.boot"  version "2.1.1.RELEASE"
}
apply plugin: 'io.spring.dependency-management'

dependencies {
    implementation project(":lib")
    implementation('org.springframework.boot:spring-boot-starter-web')
    testImplementation('org.springframework.boot:spring-boot-starter-test')
    implementation ('mysql:mysql-connector-java')
    // ...
}

编辑根据你的评论:如果lib项目需要Spring Data相关内容,则应按以下方式应用io.spring.dependency-management(详见Spring参考指南中的更多细节)。

plugins{
    id 'java-library'
    id "org.springframework.boot"  version "2.1.1.RELEASE" apply false
}
apply plugin: 'io.spring.dependency-management'

dependencyManagement {
    imports {
        mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
    }
}

dependencies {
    implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 
    // lib dependencies
}

2
“lib”是一个库,其中包含处理JPA的“common”(例如可重用)代码。因此,“lib”需要在Spring中具有依赖关系,但不打算作为可执行文件。第二个项目(“test-project”)将“lib”作为编译依赖项引用,并打算作为可执行文件(Spring Boot)。 - Illidan
4
正如我在答案中所说的那样,如果你需要在lib中使用与Spring相关的依赖,你只需要应用io.spring.dependency-management插件,而不是spring-boot插件。我已经更新了我的答案。 - M.Ricciuti
"dependencyManagement" 部分缺失,现在已经可以编译了。谢谢。 - Illidan
优秀的关注点分离答案。并将(仅)抽象SLF4J抽象jar放在“较低项目”中。谢谢。 - granadaCoder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接