Gradle多模块案例

wen java案例 2

本文目录导读:

Gradle多模块案例

  1. 项目结构
  2. settings.gradle
  3. 根目录 build.gradle
  4. 各模块 build.gradle
  5. buildSrc 自定义构建逻辑(可选)
  6. gradle.properties
  7. 示例代码
  8. 常用命令
  9. 最佳实践建议

我来提供一个Gradle多模块项目的完整案例,展示常见的Java项目结构。

项目结构

my-project/
├── build.gradle          // 根项目构建文件
├── settings.gradle       // 项目设置
├── gradle.properties     // 全局属性
├── buildSrc/            // 自定义构建逻辑(可选)
│   └── src/main/groovy/
│       └── myproject.gradle
├── common/              // 公共模块
│   ├── build.gradle
│   └── src/main/java/
├── domain/              // 领域模块
│   ├── build.gradle
│   └── src/main/java/
├── repository/          // 数据访问模块
│   ├── build.gradle
│   └── src/main/java/
├── service/             // 业务服务模块
│   ├── build.gradle
│   └── src/main/java/
├── web/                 // Web模块
│   ├── build.gradle
│   └── src/main/java/
└── app/                 // 主应用模块
    ├── build.gradle
    └── src/main/java/

settings.gradle

rootProject.name = 'my-project'
// 包含所有子模块
include 'common'
include 'domain'
include 'repository'
include 'service'
include 'web'
include 'app'
// 设置项目目录(可选)
// project(':common').projectDir = file('commons/common-lib')

根目录 build.gradle

// 使用插件管理方式
buildscript {
    repositories {
        mavenCentral()
        gradlePluginPortal()
    }
    dependencies {
        // 可以在这里添加构建脚本依赖
    }
}
// 所有子模块共有的配置
allprojects {
    group = 'com.example'
    version = '1.0.0'
    repositories {
        mavenCentral()
        maven { url 'https://maven.aliyun.com/repository/public' }
    }
}
// 子模块通用配置
subprojects {
    apply plugin: 'java'
    apply plugin: 'java-library'
    java {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
    tasks.withType(JavaCompile) {
        options.encoding = 'UTF-8'
        options.compilerArgs += ['-Xlint:unchecked', '-Xlint:deprecation']
    }
    tasks.withType(Test) {
        useJUnitPlatform()
        testLogging {
            events "passed", "skipped", "failed"
        }
    }
    dependencies {
        testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.0'
        testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.0'
        testImplementation 'org.mockito:mockito-core:5.7.0'
        testImplementation 'org.mockito:mockito-junit-jupiter:5.7.0'
    }
}
// 统一依赖管理
ext {
    springVersion = '6.1.5'
    lombokVersion = '1.18.30'
    slf4jVersion = '2.0.13'
    jacksonVersion = '2.16.1'
}

各模块 build.gradle

common/build.gradle

dependencies {
    // 通用工具类,无特殊依赖
    api 'org.apache.commons:commons-lang3:3.14.0'
    api 'org.apache.commons:commons-collections4:4.4'
    // 日志
    implementation "org.slf4j:slf4j-api:${slf4jVersion}"
}

domain/build.gradle

dependencies {
    // 依赖common模块
    api project(':common')
    // JPA注解
    api 'jakarta.persistence:jakarta.persistence-api:3.1.0'
    // 验证
    api 'jakarta.validation:jakarta.validation-api:3.0.2'
    // Lombok
    compileOnly "org.projectlombok:lombok:${lombokVersion}"
    annotationProcessor "org.projectlombok:lombok:${lombokVersion}"
}

repository/build.gradle

dependencies {
    api project(':domain')
    // Spring Data
    api 'org.springframework.data:spring-data-jpa:3.2.5'
    // 数据库驱动
    runtimeOnly 'com.h2database:h2:2.2.224'
    runtimeOnly 'org.postgresql:postgresql:42.7.2'
    // 连接池
    implementation 'com.zaxxer:HikariCP:5.1.0'
}

service/build.gradle

dependencies {
    api project(':repository')
    // Spring
    api 'org.springframework:spring-context:6.1.5'
    api 'org.springframework:spring-tx:6.1.5'
    // 事务管理
    implementation 'org.springframework:spring-aspects:6.1.5'
    // 缓存(可选)
    implementation 'org.springframework:spring-cache:6.1.5'
    implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8'
    // 测试依赖
    testImplementation 'org.springframework:spring-test:6.1.5'
}

web/build.gradle

apply plugin: 'war'  // 如果是war打包
dependencies {
    api project(':service')
    // Web框架
    implementation 'org.springframework:spring-webmvc:6.1.5'
    // JSON处理
    implementation "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}"
    implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:${jacksonVersion}"
    // 安全(可选)
    implementation 'org.springframework.security:spring-security-web:6.2.2'
    implementation 'org.springframework.security:spring-security-config:6.2.2'
    // JWT
    implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
    runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3'
    runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.3'
    // Servlet API
    providedCompile 'jakarta.servlet:jakarta.servlet-api:6.0.0'
}

app/build.gradle

apply plugin: 'application'
mainClassName = 'com.example.MainApplication'
dependencies {
    implementation project(':web')
    // 嵌入式服务器
    implementation 'org.apache.tomcat.embed:tomcat-embed-core:10.1.19'
    implementation 'org.apache.tomcat.embed:tomcat-embed-jasper:10.1.19'
    // 配置管理
    implementation 'org.yaml:snakeyaml:2.2'
}
// 应用配置
application {
    applicationDefaultJvmArgs = [
        '-Xms256m',
        '-Xmx512m',
        '-XX:MetaspaceSize=128m'
    ]
    applicationDefaultJvmArgs += ['-Dfile.encoding=UTF-8']
}
// 打包配置
distributions {
    main {
        distributionBaseName = 'my-app'
        contents {
            from('src/main/resources') {
                into 'conf'
            }
        }
    }
}
// 自定义任务示例
task printProjectInfo {
    doLast {
        println "Project: ${project.name}"
        println "Version: ${project.version}"
        println "Group: ${project.group}"
    }
}

buildSrc 自定义构建逻辑(可选)

buildSrc/build.gradle

plugins {
    id 'groovy'
}
repositories {
    mavenCentral()
}

buildSrc/src/main/groovy/myproject.gradle

// 自定义插件逻辑
class MyProjectPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.task('hello') {
            doLast {
                println "Hello from ${project.name}"
            }
        }
        // 定义公共依赖
        project.dependencies {
            implementation 'com.google.guava:guava:33.0.0-jre'
        }
    }
}

gradle.properties

# 项目属性
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.daemon=true
# 项目版本
version=1.0.0
group=com.example
# 编码
encoding=UTF-8

示例代码

common 模块工具类

// common/src/main/java/com/example/common/util/StringUtils.java
package com.example.common.util;
public class StringUtils {
    public static boolean isNullOrEmpty(String str) {
        return str == null || str.trim().isEmpty();
    }
    public static String defaultIfEmpty(String str, String defaultStr) {
        return isNullOrEmpty(str) ? defaultStr : str;
    }
}

domain 模块实体

// domain/src/main/java/com/example/domain/entity/User.java
package com.example.domain.entity;
import lombok.Data;
import javax.persistence.*;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(nullable = false, unique = true)
    private String username;
    @Column(nullable = false)
    private String email;
    @Column(name = "created_at")
    private LocalDateTime createdAt;
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;
    @PrePersist
    protected void onCreate() {
        createdAt = LocalDateTime.now();
        updatedAt = LocalDateTime.now();
    }
    @PreUpdate
    protected void onUpdate() {
        updatedAt = LocalDateTime.now();
    }
}

repository 模块

// repository/src/main/java/com/example/repository/UserRepository.java
package com.example.repository;
import com.example.domain.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);
    Optional<User> findByEmail(String email);
    boolean existsByUsername(String username);
}

service 模块

// service/src/main/java/com/example/service/UserService.java
package com.example.service;
import com.example.domain.entity.User;
import com.example.repository.UserRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
public class UserService {
    private final UserRepository userRepository;
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    public User createUser(User user) {
        if (userRepository.existsByUsername(user.getUsername())) {
            throw new RuntimeException("Username already exists");
        }
        return userRepository.save(user);
    }
    public User getUserById(Long id) {
        return userRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("User not found: " + id));
    }
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
    public User updateUser(Long id, User userDetails) {
        User user = getUserById(id);
        user.setEmail(userDetails.getEmail());
        user.setUsername(userDetails.getUsername());
        return userRepository.save(user);
    }
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}

web 模块控制器

// web/src/main/java/com/example/web/controller/UserController.java
package com.example.web.controller;
import com.example.domain.entity.User;
import com.example.service.UserService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/users")
public class UserController {
    private final UserService userService;
    public UserController(UserService userService) {
        this.userService = userService;
    }
    @GetMapping
    public ResponseEntity<List<User>> getAllUsers() {
        return ResponseEntity.ok(userService.getAllUsers());
    }
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        return ResponseEntity.ok(userService.getUserById(id));
    }
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        return ResponseEntity.status(HttpStatus.CREATED)
            .body(userService.createUser(user));
    }
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {
        return ResponseEntity.ok(userService.updateUser(id, user));
    }
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return ResponseEntity.noContent().build();
    }
}

app 模块主类

// app/src/main/java/com/example/MainApplication.java
package com.example;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.example.web.config.WebConfig;
public class MainApplication {
    public static void main(String[] args) {
        try (AnnotationConfigApplicationContext context = 
                new AnnotationConfigApplicationContext(WebConfig.class)) {
            System.out.println("Application started successfully!");
        }
    }
}

常用命令

# 构建所有模块
gradle build
# 构建特定模块
gradle :common:build
gradle :service:build
# 运行测试
gradle test
gradle :service:test
# 运行应用
gradle :app:run
# 清理构建文件
gradle clean
# 查看项目结构
gradle projects
# 查看模块依赖
gradle dependencies
# 自定义任务
gradle :app:printProjectInfo
gradle hello
# 打包构建
gradle assemble
gradle :web:war
# IDE支持
gradle idea
gradle eclipse

最佳实践建议

  1. 模块依赖要保持清晰:避免循环依赖
  2. 合理使用api vs implementation:公共API上游模块用api,内部实现用implementation
  3. 统一版本管理:使用ext或version catalog管理依赖版本
  4. 按层分包:每个模块内按功能分层
  5. 配置共享:使用buildSrc或自定义脚本共享配置

这只是基础案例,你可以根据实际需求调整模块划分和依赖关系。

抱歉,评论功能暂时关闭!