Gradle 高级篇之构建多模块项目的方法

基于 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 文件中,前面把这个文件删除了,这里可以选一个子模块的该文件复制出来。

修改方法:

  1. plugins下添加一个subprojects,将下面内容都复制到里面。
  2. 添加一个apply,将plugins中的插件进行应用。
  3. 修改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 模块生效了。

相关推荐
_院长大人_35 分钟前
SpringBoot + 百度内容安全实战:自定义注解 + AOP 实现统一内容审核(支持文本 / 图片 / 视频 + 白名单 + 动态开关)
spring boot·安全·音视频
yzq-38411 小时前
Websocket两台服务器之间的通信
spring boot·websocket·网络协议
摇滚侠2 小时前
Spring Boot3零基础教程,SpringSecurity 测试,笔记81
spring boot·笔记·后端
摇滚侠3 小时前
Spring Boot3零基础教程,定制 Health 健康端点,笔记83
spring boot·笔记·spring
一 乐6 小时前
商城推荐系统|基于SprinBoot+vue的商城推荐系统(源码+数据库+文档)
前端·数据库·vue.js·spring boot·后端·商城推荐系统
后端小张7 小时前
【JAVA 进阶】Mybatis-Plus 实战使用与最佳实践
java·spring boot·spring·spring cloud·tomcat·mybatis·mybatis plus
摇滚侠9 小时前
Spring Boot3零基础教程,SpringApplication 自定义 banner,笔记54
java·spring boot·笔记
摇滚侠9 小时前
Spring Boot3零基础教程,Spring Boot 完成了哪些Spring MVC 自动配置,笔记49
spring boot·spring·mvc
摇滚侠12 小时前
Spring Boot3零基础教程,KafkaTemplate 发送消息,笔记77
java·spring boot·笔记·后端·kafka
计算机学长felix15 小时前
基于SpringBoot的“面向校园的助力跑腿系统”的设计与实现(源码+数据库+文档+PPT)
数据库·spring boot·后端