Gradle多模块项目中Scala子模块依赖Kotlin子模块构建失败求助
解决Sub2依赖Sub1时的Spring Boot依赖版本缺失问题
看起来你遇到的问题核心在于Sub1作为Spring Boot应用模块的配置方式,导致其依赖无法正确传递给Scala模块Sub2,具体来说有两个关键点:
- Sub1使用了
org.springframework.boot插件,这个插件默认会生成可执行的bootJar而非普通库jar,并且会修改依赖的传递性,使得下游模块(比如Sub2)无法获取到Spring Boot starter依赖的版本信息。 - Sub1的Spring Boot依赖版本由
io.spring.dependency-management插件管理,但Sub2没有应用这个插件,也没有引入Spring Boot的BOM,导致Gradle无法解析spring-boot-starter-data-jpa的版本号,从而报错Could not find org.springframework.boot:spring-boot-starter-data-jpa:.
下面提供两种可行的解决方案,你可以根据项目需求选择:
方案一:将Sub1改为Spring Boot库模块(推荐)
如果Sub1只是作为提供核心Map的工具库,不需要作为独立的Spring Boot应用运行,那么应该移除org.springframework.boot插件,改用纯库模式配置:
修改sub1/build.gradle.kts:
plugins { id("org.jetbrains.kotlin.plugin.spring") id("org.jetbrains.kotlin.plugin.jpa") id("io.spring.dependency-management") // 保留版本管理插件 id("org.jlleitschuh.gradle.ktlint") } // 引入Spring Boot BOM来统一管理依赖版本 dependencyManagement { imports { // 确保根项目的gradle.properties中配置了springBootVersion属性,比如springBootVersion=2.7.15 mavenBom("org.springframework.boot:spring-boot-dependencies:${project.properties["springBootVersion"]}") } } dependencies { // Kotlin基础依赖 implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-noarg") // Spring Boot相关依赖(作为库使用) implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-autoconfigure") // 若需要自动配置能力 implementation("com.fasterxml.jackson.module:jackson-module-kotlin") implementation("javax.persistence:javax.persistence-api") runtimeOnly("mysql:mysql-connector-java") }
这样修改后,Sub1会生成普通的库jar,所有implementation依赖会正确传递给Sub2,同时依赖版本由Spring Boot BOM统一管理,Sub2不需要额外配置就能解析版本。
方案二:保留Sub1为Spring Boot应用,同时提供可依赖的库jar
如果Sub1需要作为独立Spring Boot应用运行,同时要被Sub2依赖,那么需要配置Sub1生成两个jar:一个可执行的bootJar,一个普通的库jar,并让后者作为对外依赖的artifact:
第一步:修改Sub1的配置
修改sub1/build.gradle.kts:
plugins { id("org.jetbrains.kotlin.plugin.spring") id("org.jetbrains.kotlin.plugin.jpa") id("org.springframework.boot") id("io.spring.dependency-management") id("org.jlleitschuh.gradle.ktlint") } // 启用普通jar任务,并设置为主要依赖 artifact tasks.jar { enabled = true archiveClassifier.set("") // 移除默认的classifier,让这个jar成为默认产物 } // 给可执行jar添加classifier,避免和普通jar冲突 tasks.bootJar { archiveClassifier.set("boot") } dependencies { // 原有的依赖保持不变 implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-noarg") implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") implementation("javax.persistence:javax.persistence-api") runtimeOnly("mysql:mysql-connector-java") }
第二步:修改Sub2的配置
Sub2需要引入Spring Boot的BOM来解析依赖版本,所以添加io.spring.dependency-management插件并配置BOM:
plugins { id("com.github.johnrengelman.shadow") id("application") id("scala") id("com.github.maiflai.scalatest") id("io.spring.dependency-management") // 添加版本管理插件 } // 引入Spring Boot BOM dependencyManagement { imports { mavenBom("org.springframework.boot:spring-boot-dependencies:${project.properties["springBootVersion"]}") } } dependencies { implementation(project(":sub1")) implementation("org.scala-lang:scala-library:2.12.11") testImplementation("org.scalatest:scalatest_2.12:3.2.3") testImplementation("org.scalatestplus:junit-4-13_2.12:3.2.3.0") testRuntimeOnly("com.vladsch.flexmark:flexmark-all:0.35.10") } // 其余配置保持不变 application { mainClass.set("my.application.path") } tasks.withType<ScalaCompile>().configureEach { scalaCompileOptions.additionalParameters = listOf("-feature") } tasks.withType<JavaCompile>().configureEach { options.encoding = "UTF-8" }
最后,别忘了在根项目的gradle.properties中添加Spring Boot版本配置,比如:
springBootVersion=2.7.15 kotlinVersion=1.6.21
这样配置后,Sub2就能正确解析Sub1传递过来的Spring Boot依赖版本,构建也就不会报错了。
内容的提问来源于stack exchange,提问作者taegyun kim




