基于 IDEA 创建 Gradle 多模块项目。
- IDEA 版本:2023.3.4
- SpringBoot 版本:3.5.3
- Gradle 版本:gradle-8.12.1
- JDK 版本:jdk-21.0.7
1. 创建父项目
1.1. 新建项目
文件 -> 新建 -> 项目
输入项目名称:gradle-multi-module-demo。

点击下一步,创建父项目,这里什么都没选。

点击创建,就建好了一个 SpringBoot 项目。
1.2. 修改项目
我们是要创建多模块项目,所以作为父项目,有些内容是可以删除的。下图中选中的内容可以删除。
项目目录下仅保留了:.gradle \ .idea \ .gitattributes \ .gitignore \ setting.gradle

删除后的项目结构:

2. 创建子模块
2.1. 创建模块
选中父项目 -> 新建 -> 模块
输入模块名称:demo-core。(这里模块名称最好是一个单词,多个单词的话注意修改软件包名称,多个单词间加点号)

点击下一步,作为示例项目,我仅选择了 lombok 和 spring web。

点击创建,就建好了一个 SpringBoot 模块。
2.2. 修改模块
创建好子模块后,需要在右上角的 Gradle 下删除最外层的子模块目录。

然后将子模块包含到父项目下:

刷新后,在右上角的 Gradle 下的父项目下能看到这个子模块了。

删除子模块的settings.gradle
文件。
使用同样的方法再创建一个子模块demo-mgmt
:


因为我选的依赖一样,所以这两个子模块的 build.gradle 内容一样:
gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.5.3'
id 'io.spring.dependency-management' version '1.1.7'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
3. 提取公共配置到父项目
现在发现两个子模块的 build.gradle 内容基本一样,所以可以把这些相同的配置提到父项目的 build.gradle 文件中,前面把这个文件删除了,这里可以选一个子模块的该文件复制出来。
修改方法:
- 在
plugins
下添加一个subprojects
,将下面内容都复制到里面。 - 添加一个
apply
,将plugins
中的插件进行应用。 - 修改
dependencies
中的内容,仅保留子模块们共用的依赖。
修改完的 build.gradle 内容:
gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.5.3'
id 'io.spring.dependency-management' version '1.1.7'
}
subprojects {
apply {
plugin('java')
plugin('org.springframework.boot')
plugin('io.spring.dependency-management')
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
}
子模块的 build.gradle 文件内容修改,排除共用的依赖,仅保留单独的依赖(分别加了两个不同的依赖)。
两个子模块的 build.gradle 文件内容如下:
gradle
dependencies {
implementation("com.alibaba.fastjson2:fastjson2:2.0.57")
}
gradle
dependencies {
implementation 'cn.hutool:hutool-all:5.8.38'
}
4. 创建公共子模块
上面内容是对公共配置抽取,现在需要搭建一个公共代码子模块:


创建完毕后,参考 2.2,同样的修改方式

接下来修改 common 模块的 build.gradle 文件:
gradle
plugins {
id 'java-library'
}
接下来修改父项目的 build.gradle 文件,添加一个判断引入,表示非 common 模块都引入 common 模块:
gradle
if (project.name != 'demo-common'){
dependencies {
implementation project(':demo-common')
}
}
修改完的父项目的 build.gradle 文件内容:
gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.5.3'
id 'io.spring.dependency-management' version '1.1.7'
}
subprojects {
apply {
plugin('java')
plugin('org.springframework.boot')
plugin('io.spring.dependency-management')
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
if (project.name != 'demo-common'){
dependencies {
implementation project(':demo-common')
}
}
tasks.named('test') {
useJUnitPlatform()
}
}
实际上,可以在需要依赖 common 的模块中直接添加依赖即可,能更灵活一些。
5. 测试公共子模块
首先在 common 模块配置一个全局异常拦截类:
java
package com.example.democommon.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @author wangbo
* @since 2025/7/13
*/
@Slf4j
@RestControllerAdvice
public class GlobalControllerAdvice {
@ExceptionHandler
public ProblemDetail exceptionHandler(Exception e){
log.info("==============");
log.atError().setMessage(e::getMessage).setCause(e).log();
return ProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage());
}
}
在 mgmt 模块导入该类:
Java
package com.example.demomgmt;
import com.example.democommon.config.GlobalControllerAdvice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
@Import({GlobalControllerAdvice.class})
@SpringBootApplication
public class DemoMgmtApplication {
public static void main(String[] args) {
SpringApplication.run(DemoMgmtApplication.class, args);
}
}
在 demo-mgmt 模块中创建一个 Controller 类,写上一个异常方法,启动项目,看异常是否会被拦截。
java
package com.example.demomgmt.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author wangbo
* @since 2025/7/13
*/
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/a")
public String test1(){
log.info("aaaaa");
return "aaaaa";
}
@GetMapping("/b")
public String test2(){
log.info("bbbbb");
int i = 1 / 0;
return "bbbbb";
}
}
测试会被拦截,证明 common 模块中的全局异常拦截对 mgmt 模块生效了。