【Java】Gradle 多模块项目实战:Spring Boot 微服务搭建全流程

Gradle 于 2007 年首次发布,并于 2011 年被 Google 选为 Android 官方构建工具。相较于 XML,其采用 Groovy 语言实现了更简洁的语法,配合增量构建和缓存机制,显著提升了开发与发布阶段的运行效率。[研究数据表明,Gradle 在构建 Spring Boot 项目时速度优于 Maven](#研究数据表明,Gradle 在构建 Spring Boot 项目时速度优于 Maven)1。

随着云原生和微服务架构的普及,系统通常由多个模块组成,因此掌握这一构建工具尤为重要。本文提供的多模块 Gradle 项目搭建方案,既适用于新建项目,也能支持从 Maven 迁移的场景,帮助开发者快速落地使用。

目录

开发环境

开发流程

  1. 创建父子工程目录
    父目录为multi-gradle,两个子目录,一个为购物服务,一个为外卖服务,购物服务目录为shop-service,外卖服务为takeout-service.
  2. 配置Gradle Wrapper,见gradle-wrapper.properties
    由于从 Gradle 官网下载较慢,此处通过阿里巴巴开源镜像站加速下载,后续的组件和依赖中均使用了阿里巴巴开源镜像站用于加速,做gradle build时即会开始下载
  3. 编写父工程构建脚本,见build.gradle
    脚本分为三部分:
    • Gradle 构建自身依赖(使用 spring-boot-gradle-plugin)。
    • 所有工程的公共配置(包括组名和版本号)。
    • 子工程的独立配置(包括 Java 版本、插件和依赖管理)。
  4. 编写父工程设置脚本,设置好子工程,见settings.gradle
    设置了两个子工程,分别是购物和外卖,且子工程名称与子项目目录名完全一致.
  5. 编写购物服务子工程构建脚本,见shop-service/build.gradle
    添加了spring-boot-starter-webmvc等依赖
  6. 编写购物服务子工程应用代码,见ShopServiceApplication.java
    编写一个spring boot启动主方法和一个可响应hello方法
  7. 同理编写外卖服务子工程的构建脚本和应用代码,见takeout-service/build.gradle和TakeoutServiceAppliction.java
    参考第六步和第七步,根据不同的业务
  8. 运行gradle build
  9. 编写购物和外卖的应用配置并启动购物和外卖服务
    购物服务配置好端口号为8081,应用名为shop-service,见application.yml
    外卖服务配置好端口号为8080,应用名为takeout-service,见application.yml
    同时启动两个服务

运行效果

启动购物服务图

启动外卖服务图

配置与代码

工程目录结构

nix 复制代码
multi-gradle/
├── build.gradle                # 项目构建脚本(Groovy DSL)
├── settings.gradle             # 项目设置文件,定义包含的子模块
├── gradle.properties           # 项目级 Gradle 配置属性
├── gradlew                     # Gradle 包装器脚本(Unix/Linux)
├── gradlew.bat                 # Gradle 包装器脚本(Windows)
├── gradle/                     # 包装器相关文件
│   └── wrapper/
│       └── gradle-wrapper.properties
└── shop-service/                  # 子模块 购物
    ├── build.gradle            # 子模块构建脚本
    └── src/                    # 子模块源代码目录
        ├── main/
        │   └── com.example.ShopServiceApplication
        └── test/
└── takeout-service/                  # 子模块 外卖
    ├── build.gradle            # 子模块构建脚本
    └── src/                    # 子模块源代码目录
        ├── main/
        │   └── com.example.TakeoutServiceApplication
        └── test/

gradle-wrapper.properties

其中gradle组件使用了国内阿里云的镜像

properties 复制代码
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://mirrors.aliyun.com/gradle/distributions/v9.3.1/gradle-9.3.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

settings.gradle

groovy 复制代码
// 注册所有微服务子项目,名称与子项目目录名完全一致
include  'takeout-service','shop-service'

build.gradle

groovy 复制代码
// 根项目 build.gradle(Groovy DSL)
// ########## 核心1:buildscript 声明插件依赖(Gradle构建自身的依赖)##########
buildscript {
    // 插件仓库(必须配置,拉取Spring Boot插件)
    repositories {
        mavenLocal()
        // 第一步:优先从阿里云镜像拉取(速度快)
        maven { url = 'https://maven.aliyun.com/repository/public/' }
        maven { url = 'https://maven.aliyun.com/repository/gradle-plugin' }
        // 第二步:镜像未找到时,官方仓库兜底(可选)
        gradlePluginPortal()
        mavenCentral()
    }
    // 声明插件的Maven坐标(group:name:version)
    dependencies {
        classpath "org.springframework.boot:spring-boot-gradle-plugin:4.0.2"
    }
}

// ########## 全局公共配置 ##########
allprojects {
    group = 'com.example'
    version = '0.1.0'
    repositories {
        maven { url = 'https://maven.aliyun.com/repository/public/' }
        mavenLocal()
        mavenCentral()
    }
}
// ########## 核心2:subprojects 中统一应用插件(无id()方法,用apply plugin)##########
subprojects {
    // 应用核心插件+Spring Boot插件(无语法冲突)
    apply plugin: 'java'
    apply plugin: 'maven-publish'
    apply plugin: 'org.springframework.boot'
    apply plugin: 'io.spring.dependency-management'
    java {
        toolchain {
            languageVersion = JavaLanguageVersion.of(25) // 所有子模块统一使用 Java 25
        }
    }

    // 全局版本常量+公共依赖(与之前一致)
    dependencies {
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
//         Gradle 9.x 需显式声明JUnit 5平台启动器
//        testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
    }

    // Spring Cloud 版本统一(可选)
    dependencyManagement {
        imports {
            mavenBom "org.springframework.cloud:spring-cloud-dependencies:2025.1.0"
        }
    }
    // 核心配置:启用JUnit 5平台,让Gradle识别JUnit 5的@Test注解
    tasks.test {
        useJUnitPlatform() // 必须添加,否则Gradle无法扫描JUnit 5测试用例
    }
}

shop-service/build.gradle

复制代码
// 子项目 shop-service/build.gradle(Groovy DSL)
// 无需重复写repositories、group、version、公共依赖!
// 仅写当前微服务特有的依赖/配置

dependencies {
    // 自身业务特有依赖(如用户模块的持久层、服务层依赖)
    implementation 'org.springframework.boot:spring-boot-starter-webmvc'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    runtimeOnly("com.h2database:h2")
}

// 可选:覆盖全局配置(如需单独指定版本/插件)
// version = '1.0.1' // 覆盖根项目的version

ShopServiceApplication.java

java 复制代码
package com.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.service.annotation.GetExchange;
/// 购物服务
@RestController
@SpringBootApplication
public class ShopServiceApplication {
    /// 构造方法
    public ShopServiceApplication(){

    }

    private static final Logger log = LoggerFactory.getLogger(ShopServiceApplication.class);

    /**
     * 主方法
     * @param args  命令行参数
     */
    public static void main(String[] args) {
        SpringApplication.run(ShopServiceApplication.class, args);
    }

    /**
     * hello
     *
     * @return hello
     */
    @GetExchange("hello")
    public String hello() {
        log.info("hello");
        return "hello";
    }
}

shop-service/src/main/resources/application.yml

yaml 复制代码
spring:
  application:
    name: shop-service
  datasource:
    url: jdbc:h2:mem:${spring.application.name}
server:
  port: 8081

takeout-service/build.gradle

groovy 复制代码
// 子项目 taskout-service/build.gradle(Groovy DSL)
// 无需重复写repositories、group、version、公共依赖!
// 仅写当前微服务特有的依赖/配置

dependencies {
    // 自身业务特有依赖(如用户模块的持久层、服务层依赖)
    implementation 'org.springframework.boot:spring-boot-starter-webmvc'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    runtimeOnly("com.h2database:h2")
}

// 可选:覆盖全局配置(如需单独指定版本/插件)
// version = '1.0.1' // 覆盖根项目的version

TakeoutServiceApplication.java

java 复制代码
package com.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.service.annotation.GetExchange;

/// 外卖服务
@RestController
@SpringBootApplication
public class TakeoutServiceApplication {
    /// 构造方法
    public TakeoutServiceApplication() {

    }

    private static final Logger log = LoggerFactory.getLogger(TakeoutServiceApplication.class);

    /**
     * 主方法
     * @param args  命令行参数
     */
    public static void main(String[] args) {
        SpringApplication.run(TakeoutServiceApplication.class, args);
    }

    /**
     * hello
     *
     * @return hello
     */
    @GetExchange("hello")
    public String hello() {
        log.info("hello");
        return "hello";
    }
}

takeout-service/src/main/resources/application.yml

yaml 复制代码
spring:
  application:
    name: takeout-service
  datasource:
    url: jdbc:h2:mem:${spring.application.name}

引用

1崔娟,张生月,章恒.Maven与Gradle构建工具对比分析J.科技创新与应用,2025,15(21):93-96.DOI:10.19981/j.CN23-1581/G3.2025.21.021.

相关推荐
Elastic 中国社区官方博客4 小时前
我们如何通过 70 多个拉取请求,将 OpenTelemetry Java agent 迁移到 invokedynamic
java·大数据·开发语言·elasticsearch·搜索引擎·全文检索·es
tyn1884 小时前
记录本地安装nacos服务的方法及异常
java·开发语言
步行cgn5 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
y1su5 小时前
Leetcode 字符串模板
java·数据结构·算法·leetcode·职场和发展·动态规划
我命由我123456 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法
苜蓿muxu7 小时前
Java 字符串拼接:+、StringBuilder、StringBuffer的区别
java
摇滚侠7 小时前
《Java并发编程之美》第 4 章 Java 并发包中原子操作类原理剖析 阅读笔记 7
java·笔记·python
旋律4148 小时前
同义方法区别(增加类与删除类)
java·后端
学到老活到老8 小时前
方法执行完了,对象为什么还占着内存?
java·jvm