欢迎来到窥视未来的博客

https://github.com/lwx57280 https://gitee.com/li_VillageHead

Gradle 多模块项目转 Maven POM 文件指南

核心目标

将现有的 Gradle 多模块项目结构转换为 Maven 兼容的 pom.xml 文件,为项目迁移或双构建系统支持做准备。

环境与前提

  • IDE: IntelliJ IDEA 2024

  • 构建工具: Gradle 8.2

  • JDK: 11

重要提示: 确保项目 build.gradle 中的依赖配置清晰有序,避免依赖混乱导致转换错误。

基础概念

转换原理

Gradle 的 maven-publish 插件能够分析项目的依赖关系和配置,自动生成对应的 Maven POM 文件。这个过程主要转换:

  • 项目坐标 (groupId, artifactId, version)

  • 依赖项及其作用域

  • 基础项目信息

限制与注意事项

  • 自动化转换主要处理依赖关系

  • Maven 的聚合与继承结构需要手动设计

  • 插件配置和构建流程需要额外处理

换步骤

添加必要插件

在每个需要生成 POM 的模块的 build.gradle 文件中,添加 javamaven-publish 插件

// 示例:单个模块的 build.gradle 顶部
plugins {
    id 'java'
    id 'maven-publish'
    // 其他插件...
}

  

配置发布出版物

在同一个 build.gradle 文件中,添加 publishing 块来定义 Maven 发布物。

publishing {
    publications {
        // 'mavenJava' 是自定义发布物名称,可更改
        mavenJava(MavenPublication) {
            // 关键配置:使用 Java 组件自动生成依赖等信息
            from components.java
        }
    }
}

 

执行生成命令

配置完成后,在终端执行以下 Gradle 任务来生成 POM 文件。

# 生成 POM 文件
gradle generatePomFileForMavenJavaPublication

 

理生成的文件

生成的 POM 文件位于模块的 build 目录下:

  1. 定位生成的文件:build/publications/mavenJava/pom-default.xml

  2. 复制到模块根目录并重命名为 pom.xml

最终使用

将生成的 pom-default.xml 文件复制到模块的根目录,并重命名为 pom.xml,即可作为该模块的 Maven 构建基础。

 

多模块项目转换

项目结构示例

假设项目结构如下:

## 工程结构 [端口可根据实际情况做调整]
```lua
cow-admin        			 		-- 项目根目录
├── auth-server     	 	 		-- 认证中心服务[8083]
├── common    	 	    			-- 公共基础库
├  ├── bi							-- bi   
├  ├── db							-- db    
├  ├── domain    	 				-- 领域模型
├  ├── locale             			-- locale
├  ├── message    	    			-- message
├  └── meta          				-- meta 枚举元数据
├  └── netty  						-- netty
├  └── rsync  						-- rsync
├  └── security  				 	-- security
├  └── table  				 		-- table
├── gateway    	 	    			-- 网关服务[7778]
├── gms-ranch    	 	    		-- gms-ranch[8091]
├── module   	 	    			-- 模块库
├  └── contract  					-- contract 合约
├  └── logic  						-- logic
├  └── model-ranch  				-- model-ranch  
├── task-ranch   	 	    		-- task-ranch
├  └── task-ranch-base  			-- task-ranch-base
├  └── task-ranch-bullring  		-- task-ranch-bullring
├  └── task-ranch-retention  		-- task-ranch-retention
├  └── task-ranch-runner  			-- task-ranch-runner
├  └── task-ranch-user  			-- task-ranch-user
├── task-runner 					-- task-runner[8081]
```

 

在根项目的 build.gradle 中:

// 在根项目的 build.gradle 中
allprojects {
    group = "com.brilljoy"   // 统一 GroupId
    version = "1.0.0-SNAPSHOT" // 统一版本号
}

 

Gradle 会自动从 project.groupproject.name (对应 ArtifactId)、project.version 获取坐标信息并写入 POM。

子模块最小配置

在每个子模块build.gradle 中,只需添加最小配置:

plugins {
    id 'java'           // 必需
    id 'maven-publish'  // 必需
}

publishing {
    publications {
        mavenJava(MavenPublication) {
            from components.java
        }
    }
}

这样就告诉 Gradle:要用 Java 组件生成一个 pom

所有模块的 POM

# 方式一:执行所有模块的发布任务(推荐)
./gradlew generatePomFileForMavenJavaPublication
​
# 方式二:分别指定模块生成
./gradlew :common:generatePomFileForMavenJavaPublication
./gradlew :common:bi:generatePomFileForMavenJavaPublication
./gradlew :gateway:generatePomFileForMavenJavaPublication
# ... 其他模块

 

完整配置示例

根项目配置

plugins {
    id 'java'
    id "maven-publish"
    id 'org.springframework.boot' version '2.5.3' apply false
    id 'io.spring.dependency-management' version '1.0.11.RELEASE' apply false
    id 'idea' // 修正:用id语法声明idea插件,替代apply plugin
}
description = "cow-admin 创奇牧场"

// 加载全局配置
apply from: rootProject.file("config.gradle")
group 'com.brilljoy.olap'
version = revision
//sourceCompatibility = '11'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

ext {
    set('springCloudVersion', "2020.0.5")
    set("springBootVersion", "2.5.9")
    set("commonsVersion", "1.15")
}
// 所有项目(主项目+子项目)配置
allprojects {
    // 指定需要的插件
    // 指定语言
    apply plugin: 'java'

    tasks.withType(JavaCompile) {
        options.release = 11 // 关键:指定编译为 Java 11 字节码(Gradle 7+ 支持)
        options.encoding = 'UTF-8'
    }

    // 配置项目信息(继承主项目)
    group group
    version version
    // 指定编码格式
    [compileJava, compileTestJava, javadoc]*.options*.encoding = 'UTF-8'

    // 配置仓库
    repositories {
        //优先从本地仓库获取
        mavenLocal()
        //阿里
        maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
        //腾讯
        maven { url 'https://mirrors.cloud.tencent.com/nexus/repository/maven-public/' }
        //华为
        maven { url 'https://mirrors.huaweicloud.com/kunpeng/maven/' }
        mavenCentral()
        gradlePluginPortal()

    }

    buildscript {
        repositories {
            maven { name "Alibaba"; url 'https://maven.aliyun.com/nexus/content/groups/public' }
            maven { name "tencent"; url 'https://mirrors.cloud.tencent.com/nexus/repository/maven-public/' }
            maven { name "goolge"; url 'https://maven.aliyun.com/nexus/content/repositories/google' }
        }
    }
}
// 子项目配置
subprojects {
    apply plugin: 'java'
    apply plugin: 'java-library'
    apply plugin: 'maven-publish'
    apply plugin: 'idea' /* 同上  让Gradle自动生成Intellij的项目文件*/
//    apply plugin: 'org.springframework.boot'
    apply plugin: 'io.spring.dependency-management'

    // 配置全局依赖版本信息
    ext {
        // 统一定义版本,后面引用
        compileJava.options.encoding = 'UTF-8'
        compileTestJava.options.encoding = 'UTF-8'
//        springVersion = "2.3.12.RELEASE"

        commonVersion = "1.0.15-SNAPSHOT"
        moduleVersion = "1.0.14-SNAPSHOT"
        easyexcelVersion = "3.1.1"
    }

    // 配置字符编码
    tasks.withType(JavaCompile) {
        options.encoding = 'UTF-8'
    }
    // dependencyManagement版本统一管理,类似于父maven的dependencyManagement
    dependencyManagement {

        dependencies {
            for(depJar in rootProject.ext.dependencies){
                dependency depJar.value
            }

            dependency("commons-codec:commons-codec:${commonsVersion}")
            dependency("org.springframework.boot:spring-boot-starter:${springBootVersion}")
            dependency("org.springframework.boot:spring-boot-starter-undertow:${springBootVersion}")
//            dependency("org.springframework.data:spring-data-commons:${springDataVersion}")
//            dependency("org.springframework.boot:spring-boot-starter-jdbc:${rootProject.ext.springBootVersion}")

            dependency "com.mysql:mysql-connector-j:8.2.0"
        }
        imports {
            // 关键:导入 Spring Boot 官方 BOM,替代手动声明单个 Starter 版本
            mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
            mavenBom "org.springframework.boot:spring-boot-dependencies:${springBootVersion}"
        }
    }

    // 子项目依赖,类似于在父maven的dependencies
    dependencies {
        // 统一声明 spring-boot-starter-test 为测试依赖
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
//        implementation(enforcedPlatform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))
        // lombok
        compileOnly 'org.projectlombok:lombok'
        annotationProcessor 'org.projectlombok:lombok'
    }
    // 开启构建bootJar
//    tasks.bootJar {
//        enabled = true
//    }
    tasks.named('test') {
        useJUnitPlatform()
    }

    // 关键:统一配置 Maven 发布逻辑(所有模块共用)
    publishing {
        publications {
            // 定义发布名称为 mavenJava(与 common 子模块保持一致)
            mavenJava(MavenPublication) {
                // 分两种情况:普通模块(common 子模块)和 Spring Boot 服务模块
                if (plugins.hasPlugin('org.springframework.boot')) {
                    // 情况 1:Spring Boot 服务模块(auth-server、gateway 等)
                    // 关联 bootJar 生成的可执行 JAR(避免默认 components.java 失效)
                    artifact tasks.bootJar
                } else {
                    // 情况 2:普通 Java 模块(common 子模块)
                    // 关联 java 组件生成的普通 JAR
                    from components.java
                }

                // 补充 POM 元数据(可选,但建议统一配置,避免 pom 缺失关键信息)
                pom {
                    name = project.name // 模块名称
                    description = "cow-admin 项目的 ${project.name} 模块" // 模块描述
                    url = "https://gitee.com/li_VillageHead/cow-admin.git" // 可选

                    // (可选)许可证、开发者信息等,按需求添加
                    licenses {
                        license {
                            name = "Apache License 2.0"
                            url = "https://www.apache.org/licenses/LICENSE-2.0.txt"
                        }
                    }
                }
            }
        }

        // 统一配置发布仓库(本地 Maven 仓库)
        repositories {
            mavenLocal()
        }
    }
    // 强制发布前先执行构建(确保 JAR 已生成)
    tasks.publishToMavenLocal.dependsOn tasks.build
}

添加完上面这段之后,执行下面的命令即可生成 pom 文件:

 

gradle generatePomFileForMyMavenPublication

生成与处理pom.xml 文件

执行生成

# 清理并生成所有模块的 POM
./gradlew clean
./gradlew publishToMavenLocal

 

处理生成的 POM

  1. 收集生成的文件

    • 各模块的 build/publications/mavenJava/pom-default.xml

    • 复制到对应模块根目录并重命名为 pom.xml

  2. 创建父 POM

    • 在根目录创建 pom.xml

    • 定义模块聚合 (<modules>)

    • 定义依赖管理 (<dependencyManagement>)

  3. 调整子模块 POM

    • 移除重复的依赖管理配置

    • 添加父模块引用 (<parent>)

    • 调整依赖作用域

示例生成的 POM 内容

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <!-- This module was also published with a richer model, Gradle metadata,  -->
  <!-- which should be used instead. Do not delete the following line which  -->
  <!-- is to indicate to Gradle or any Gradle module metadata file consumer  -->
  <!-- that they should prefer consuming it instead. -->
  <!-- do_not_remove: published-with-gradle-metadata -->
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.brilljoy.common</groupId>
  <artifactId>bi</artifactId>
  <version>1.0.15-SNAPSHOT</version>
  <dependencies>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>easyexcel</artifactId>
      <version>3.1.1</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>jakarta.persistence</groupId>
      <artifactId>jakarta.persistence-api</artifactId>
      <version>2.2.3</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-io</artifactId>
      <version>1.3.2</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.12.4</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>commons-codec</groupId>
      <artifactId>commons-codec</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.12.0</version>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>2020.0.5</version>
        <scope>import</scope>
        <type>pom</type>
      </dependency>
      <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.15</version>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
        <version>2.5.9</version>
      </dependency>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies-parent</artifactId>
        <version>2020.0.3</version>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
        <version>2.5.9</version>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <version>2.5.9</version>
      </dependency>
      <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.24</version>
      </dependency>
      <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-commons</artifactId>
        <version>2.5.8</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>

注意: 此方法主要辅助生成模块依赖列表,但对于 Maven 项目的聚合与继承结构,仍需开发者根据 Maven 的最佳实践进行手动设计和调整。

 

Gradle 项目

image

 

转换完成Maven

image

 

 

常见问题处理

  1. 依赖作用域不匹配

    • 检查 Gradle 的 implementation/api 与 Maven 的 compile/runtime 对应关系

  2. 模块间依赖问题

    • 确保子模块间依赖使用 Maven 坐标而非项目路径

  3. 插件配置缺失

    • Maven 需要显式配置插件,而 Gradle 很多功能是内置的

迁移策略

7.1 渐进式迁移

  1. 阶段一:双构建系统并存

  2. 阶段二:逐步迁移构建逻辑

  3. 阶段三:完全切换到 Maven

7.2 回滚方案

  1. 保留原始的 Gradle 配置

  2. 使用版本控制系统管理迁移过程

  3. 准备回滚脚本和文档

八、最佳实践

  1. 保持简洁:尽量使用标准的 Maven 约定,减少自定义配置

  2. 统一管理:在父 POM 中集中管理依赖版本和插件配置

  3. 逐步验证:分模块逐步验证,避免一次性大规模迁移

  4. 文档化:记录所有自定义配置和特殊处理

总结

Gradle 到 Maven 的转换是一个系统工程,自动化工具可以处理依赖关系等基础工作,但项目结构和构建逻辑需要根据 Maven 的最佳实践进行手动设计和调整。建议采用渐进式迁移策略,确保过程的平稳和可控性。

注意: 本文档提供的示例和代码需要根据实际项目情况进行调整。建议在正式迁移前在测试环境中充分验证。

 

posted on 2025-08-24 18:36  窥视未来  阅读(113)  评论(0)    收藏  举报

导航