介绍:什么是单体仓库以及为什么在Java中需要它
在Java开发世界中,存储代码主要有两种方法:单体仓库(monorepo)和多仓库(multirepo)。单体仓库是一种策略,其中项目的所有代码库(库、服务、工具、配置)都存储在一个仓库中。对于处理大型企业系统或微服务的Java开发人员来说,单体仓库正成为一种越来越流行的解决方案。
单体仓库在Java中的优势显而易见:
- 统一的依赖版本:所有模块使用相同版本的库,从而避免冲突(classpath hell)。
- 简化的重构:在一个模块中更改API会立即在所有依赖模块中可见。
- 跨变更历史:一次提交可以包含多个模块的更改,从而简化调试。
- 标准化:整个项目统一的代码风格、代码检查和CI/CD规则。
然而,单体仓库需要良好的组织。在本文中,我们将探讨如何使用Maven和Gradle在单体仓库中正确构建Java项目。
主要部分:在Java中组织单体仓库
1. 目录结构:模块化方法
单体仓库的基础是模块化结构。每个模块代表一个独立的单元(库、服务、工具)。让我们考虑一个Java项目的典型结构:
my-monorepo/├── build.gradle # 根构建文件 (Gradle)├── settings.gradle # 模块列表├── gradle.properties # 通用设置├── gradle/│ └── wrapper/├── common/ # 通用库│ ├── common-utils/ # 工具(字符串、日期)│ └── common-dto/ # 用于数据交换的DTO├── services/ # 微服务│ ├── user-service/ # 用户服务│ └── order-service/ # 订单服务├── libs/ # 内部库│ └── logging-lib/ # 日志记录库├── tests/ # 集成/端到端测试│ └── e2e-tests/└── buildSrc/ # 通用插件和配置每个模块内部都有标准的Maven/Gradle结构:
user-service/├── build.gradle├── src/│ ├── main/│ │ ├── java/│ │ │ └── com/example/user/│ │ │ ├── controller/│ │ │ ├── service/│ │ │ └── repository/│ │ └── resources/│ │ └── application.yml│ └── test/│ └── java/└── Dockerfile2. 依赖管理:Maven BOM和Gradle Version Catalog
单体仓库的主要问题是依赖版本的同步。在Java中,这有两种解决方案。
方案1:Maven BOM(物料清单)
创建一个根POM,声明所有依赖版本。子模块使用dependencyManagement:
<!-- pom.xml (根) --><dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>3.2.0</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.example</groupId> <artifactId>common-utils</artifactId> <version>1.0.0</version> </dependency> </dependencies></dependencyManagement>方案2:Gradle Version Catalog
在文件gradle/libs.versi