【Gradle】(二)多模块项目、api推送到Maven私服、及SpringBoot可执行Jar包

1.概述

在上一篇涉及初始化 Gradle 项目的相关内容里,我们充分借助 IDEA 成功构建出了一个处于最基础层面的 Java 项目。不过,需要明确的是,这样的成果距离能够满足日常开发工作的实际需求,还存在着相当大的差距。在当下的这一篇当中,我们将会基于此前构建的基础,通过创建“SpringBoot”的服务实例,全方位地展示应当如何针对 Gradle 的多模块项目予以合理有效的组织,并且在整个这一进程之中,清晰地阐释一些全新的概念。

《本篇代码Demo地址》

2.多模块项目构建

gradle-demo项目中创建三个子模块common,demo-api,demo-service,其作用分别为:

  • common:通过模块,放一些所有模块都要用到的常量、工具类等
  • demo-api:Dubbo服务对外提供的api包,供其他依赖引入。
  • demo-service:主服务,承载SpringBoot的MVC功能和Dubbo的实现,提供Http接口和RPC接口

作为演示项目,只拆分了3个模块,实际工作中可以根据需要继续拆分。

2.1.子模块创建

子模块创建方式非常简单,只需要下面的两个步骤。
在这里插入图片描述在这里插入图片描述


按这个方法创建完三个子模块,项目结构如下图所示:
在这里插入图片描述


settings.gradle中已经自动加入了子模块的引用,如果没有加入的话,也可以按下面的语法 inclue + 模块名的方式手动引入。

rootProject.name = 'gradle-demo'
include 'common'
include 'demo-api'
include 'demo-service'

2.2. SpringBoot引入

2.2.1.配置修改及启动

首先,需要在gradle.properties中定义需要使用到的插件和jar包的版本号,方便统一管理。

# 项目版本配置
group=com.ls
version=1.0.0
description=gradledemo
# Spring version
springBootVersion=2.7.18
springDenpendencyVersion=1.0.15.RELEASE
# Lombok version
lombokVersion=1.18.20

group和version是可以直接配置在这个资源文件中的,配置后能直接对所有模块生效。


其次在最外层(父模块)的build.gradle中,修改配置内容。下面是一个完整的配置文件内容,在后面的概念解释中会讲解每一步的含义。

plugins {
    id 'java'
    id 'org.springframework.boot' version "$springBootVersion" apply false
    id 'io.spring.dependency-management' version "$springDenpendencyVersion" apply false
}

allprojects {
    repositories {
        maven {
            url 'https://maven.aliyun.com/repository/public'
        }
        mavenCentral()
    }
}

subprojects {
    apply plugin: 'java'
    sourceCompatibility = JavaVersion.VERSION_1_8

    dependencies {
        compileOnly "org.projectlombok:lombok:$lombokVersion"
        annotationProcessor "org.projectlombok:lombok:$lombokVersion"
    }

}

最后,先清空子模块的build.gralde文件中的内容,再找到demo-service里面加入SpringBootWeb依赖。

apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

在这里插入图片描述
在这里插入图片描述
打印出了Tomcat端口,表示启动成功。

2.2.2.概念解释

解释一下上面配置中的各类名词及步骤的含义。

plugins

插件用于扩展 Gradle 的功能和行为,可以自动应用特定的构建逻辑、任务和配置。上一篇中已经提到了Java插件的作用,就是用于编译代码,生成jar包,执行单元测试等


上面的其中SpringBoot插件org.springframework.boot也类似于Java插件的效果,就是用来配置SpringBoot服务的打包流程,运行SpringBoot服务,生成可以执行jar包等。类似于Maven中的spring-boot-maven-plugin


另一个插件io.spring.dependency-management则主要是给SpringBoot相关的jar包提供依赖,仔细看的话,在上面的demo-service引入的依赖中并没有加入版本号。类似于Maven中的dependencyManagement功能。
总的来说,引入这个插件非常类似于在Maven中的这个操作:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.18</version>
    <relativePath/>
</parent>

至于插件后的 apply false,表示在项目中不直接生效而是在子项目中通过apply plugin:xxx 选择性的应用插件,这样使用更加灵活,既保证了统一定义插件版本,又保证了按需引入。

allprojects和subprojects

通过名字不难看出来前者是对所有项目生效,后者是对子项目生效。

  • allprojects:一般用来做一些全局配置,例如仓库配置。
  • subprojects:一般用于配置所有子项目都会使用到的通用依赖。
apply plugin

上面简单的说了一个apply plugin 的作用,就是将引入的插件在特定的模块中应用,仔细看父模块的配置:
在这里插入图片描述
在plugins中的Java插件并没有使用apply false,在subjects中依然需要使用apply plugin,这其实涉及到一个作用域的问题。

plugins中的Java插件是在跟项目中引入的,只会对根项目起作用,如果想对子模块也起作用,就需要在subprojects或者每个模块的build.gradle中通过apply plugin应用。

dependencies

这一块可以说是gradle中最常用的功能,其作用就是引入各种各样的jar包,语法规则有下面两种:

依赖配置 "groupId:artifactId:version"
依赖配置("groupId:artifactId:version")

所谓的依赖配置(transitive dependencies),是指一个项目的依赖项及其子依赖项都被引入项目的构建路径。用来确定依赖范围,依赖传递等

本篇会涉及到的几种依赖配置:

  • compileOnly:声明的依赖只在编译时可见,不包括在运行时。
  • annotationProcessor:用于在编译时处理注解的依赖。
  • implementation:声明的依赖在编译和运行时可见。
  • testImplementation:声明的依赖在测试编译和运行时可见。

以上面的配置为例,lombok的作用是简化代码,例如在源码中通过@Getter @Setter注解来替代get() set()方法,在编译的时候再生成对应的代码。也就是说,lombok只需要在编译的时候才需要用到,这里使用compileOnly这个依赖配置就非常合适。
同时,这里涉及到在gradle build 的过程中解析注解,还需要通过annotationProcessor来声明lombok需要被解析的注解,这样在编译过程中才会将@Getter处理为get()方法,否则将会被gradle忽略。


implementation 是最常用的依赖配置,它还有一种特殊的用法,即:

implementation project(':moduleXXX')

这种用法是用在多模块的项目中,让一个模块A直接依赖另一个模块B的源码,B模块源码和依赖项可以直接参与到当前模块的编译和运行过程。
这个功能是Maven中没有的一个功能,它的出现大大降低了复杂的多模块项目管理复杂度,让模块依赖关系更加清晰。

2.2.api模块

这是一个 Dubbo 的 API 模块,有两个作用:

  • 在当前项目中引入 API 里的接口,并予以实现。
  • 对外提供一个 Jar 包,提供可供调用的接口协议。

2.2.1.api模块的project引入

common模块和api功能定位不一样,但对于编码来说比较类似,下面就以api模块为例体验一下implementation project

在上面说到,这里的API模块主要是用于对外提供Dubbo请求需要的接口协议和对象,同时我们在demo-service模块中,也需要实现对应的接口。


在api中随便定义一个接口
在这里插入图片描述
切换到demo-service,依赖api模块,在build.gradle的的dependcies中加入:

implementation project(":demo-api")

这种引入方式并不需要严格的指定坐标,只需要模块的名称即可,在下面的截图中可以看到,依赖已经引用成功了。
在这里插入图片描述
此时,我们在api中再随便加个方法,看看会出现什么结果:
在这里插入图片描述在这里插入图片描述
可以看到的是,在IDAE中直接提示了接口有未实现的方法,就像是直接在当前模块编辑源码一样。相对于在Maven中,需要重新设置api的版本号,再修改service中依赖的api版本号而言,要方便很多。

PS:Maven中也可以通过SNAPSHOT模拟出类似的能力,但毕竟SNAPSHOT不是正式的jar包,不适合在生产中使用。

2.2.2.将API打包并推送到Maven私服

在 Gradle 中,其本身并不具备直接将 Jar 包推送至 Maven 私服的功能。然而,Gradle 为我们提供了相关的插件,通过运用这些插件,能够拓展出将 Jar 包推送至 Maven 私服的能力。当前,要实现此操作,我们总共需要完成四个步骤:

  • 首先,要应用 Maven 插件 maven-publish
  • 其次,对发布配置进行修改,清晰地定义发布的包的类型以及私服的具体地址。
  • 接着,明确需要推送模块的坐标,这里所说的坐标指的是 groupIdartifactIdversion
  • 最后,执行推送的操作。

应用插件

demo-api的build.gradle文件中应用Maven发布插件,写下下面的脚步时候,IDEA右侧的TASK也会相应的变化。

apply plugin: 'maven-publish'

在这里插入图片描述
这里多出了两个Task:

  • publish:发布到Maven远程仓库中
  • publishToMavenLocal:发布到Maven本地仓库

但现在这两个Task是没有作用的,因为Gradle还不知道需要将代码打成jar包还是war包,需要将构建完成的包发布到哪里。

发布配置修改

发布配置主要是解决 what 和 where 的问题,也是代码需要打包的类型和发布的位置,通过publishing块来进行配置,先看demo-api的build.gradle 配置,下面我再解释里面的含义:

apply plugin: 'maven-publish'

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

    repositories {
        maven {
            name = "mavenNexus"
            allowInsecureProtocol = true
            def releasesRepoUrl = 'http://192.168.200.101:8081/repository/maven-releases/'
            def snapshotsRepoUrl = 'http://192.168.200.101:8081/repository/maven-snapshots/'
            url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
            credentials {
                username 'admin'
                password 'admin123'
            }
        }
    }
}
  • publications:发布配置,即定义“what”,里面可以配置打包的类型,这里的 from components.java 就是把代码打成jar包,如果想要打成war包,则是 from components.web
    • demoApi:当前发布配置的命名,你可以写成任意你想要的名字,用驼峰式命名即可
  • repositories:仓库配置,即定义“where”,里面配置仓库的地址,http://192.168.200.101:8081 是我我本地启动的私服。
    • name:当前仓库在task中的名字
    • allowInsecureProtocol:作用是让Gradle忽略不安全的http地址,如果不配置这一项的话,需要保证私服的地址是https协议。
    • credentials:私服的用户名和密码

配置完成之后,task就变成了这个样子:
在这里插入图片描述
红框中的两个task分别表示的是把构建好的jar包推到Maven本地仓库和远程仓库,需要注意的是,在task中有DemoApiMavenNexus两个单词,这就是我在上面定义的name,如果定义成其他的名字,这里也会显示另外的名字。

定义坐标

在根项目的gradle.properties中,我们已经做了全局定义:

group=com.ls
version=1.0.0

也就是说,现在demo-api的坐标为:com.ls:demo-api:1.0.0,需要修改发布的版本的话,可以直接修改这个properties文件,但是由于这个文件影响的是当前项目下的所有子模块,如果只想修改demo-api的版本,其他默认的版本号保持不变话,可以在demo-api的buil.gradle中做单独的定义,例如修改为2.0.0

执行发布

一般我们发布给其他项目使用的jar,都需要将源码上传,以便对接者可以直接通过源码查看代码的注释,修改过后的最终配置如下:

apply plugin: 'maven-publish'

version = "2.0.0"

java {
    withSourcesJar()
}

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

    repositories {
        maven {
            name = "mavenNexus"
            allowInsecureProtocol = true
            def releasesRepoUrl = 'http://192.168.200.101:8081/repository/maven-releases/'
            def snapshotsRepoUrl = 'http://192.168.200.101:8081/repository/maven-snapshots/'
            url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
            credentials {
                username 'admin'
                password 'admin123'
            }
        }
    }
}

运行右侧publishDemoApiPublicationToMavenNexusRepository,可以看到执行了多个Task,最终推送到远程仓库中。
在这里插入图片描述
推送结果如下图所示:
在这里插入图片描述

2.3.构建可以运行的SpringBoot包

在上面的内容中,我们已经将demo-service在IDEA中启动了,但在实际的生产工作中,只在IDEA中启动是不够的,还需要把项目构建成为一个可运行的Jar包,以供生产发布。

demo-service的build.gradle文件中,我们应用了根项目引入的SpringBoot插件:

apply plugin: 'org.springframework.boot'

这个插件可以给gradle的task添加打包的流程,叫做bootJar,通过一个截图可以看到应用和没有应用插件的区别:
在这里插入图片描述
这里直接双击bootJar就可以完成打包,但是我们在实际生产中,可能是通过自动化脚本来进行发布的,可以通过下面的脚步完成打包:

gradlew clean bootjar -x test
  • gradlew:在根项目中有两个可执行文件,gradlewgradlew.bat,分别对应shell脚本和批处理脚本,我们大多数情况是发布在Linux环境中的,所以这里选择shell脚本
  • clean:先清空之前打的包
  • bootjar:构建SpringBoot的可执行jar包
  • -x test:打包时跳过测试阶段

需要注意的是,打包时需要从根项目进入到demo-service子模块中,所以打包的脚步就变成了这样:

cd demo-service
 ../gradlew clean bootjar -x test

在这里插入图片描述

打包成功,接下来看看能否运行,文件在{子项目目录}/build/libs中,从下图可以看到启动成功。
在这里插入图片描述

3.总结

本篇主要讲解了如何在 Gradle 中引入 Spring Boot,并创建一个多模块项目,同时讲解了发布的两种形式,即可执行 jar 包的生成与构件的生成和发布。

  • 演示了如何创建多模块项目,同时对插件、依赖等概念做了简单解释。
  • 体验了 Gradle 插件的作用,通过 Spring Boot 插件,完成了一次可运行 jar 包的构建生成并成功启动。
  • 对项目中子模块之间的特殊依赖“implementation project”做了讲解,可用这种方式直接依赖源码,无需频繁在依赖中修改版本号。
  • 讲述了如何通过 Maven 的发布插件将 jar 包推送到 Maven 私服中。

到目前为止,已经能够通过 Gradle 完成大部分研发工作了。在下一篇文章中将会讲到 Gradle 的依赖范围、依赖路径、依赖传递等特性。

  • 24
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
Gradle的多模块项目中使用Spring Boot打包时,需要在每个模块中配置相应的构建脚本build.gradle文件。以下是一个示例: 1. 在根目录的build.gradle中添加以下代码: ```groovy subprojects { apply plugin: 'java' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' repositories { mavenCentral() } dependencies { compile('org.springframework.boot:spring-boot-starter-web') testCompile('org.springframework.boot:spring-boot-starter-test') } jar { baseName = "${project.name}" version = "${project.version}" } bootJar { baseName = "${project.name}" version = "${project.version}" } } ``` 2. 在每个模块的build.gradle中添加以下代码: ```groovy apply plugin: 'java' apply plugin: 'io.spring.dependency-management' dependencies { implementation project(':module-name') compile('org.springframework.boot:spring-boot-starter-web') testCompile('org.springframework.boot:spring-boot-starter-test') } jar { baseName = "${project.name}" version = "${project.version}" } bootJar { baseName = "${project.name}" version = "${project.version}" } ``` 其中,`module-name`为该模块依赖的其他模块的名称。 3. 在根目录下执行`./gradlew build`命令即可打包所有模块。在每个模块的build/libs目录下会生成相应的jar包和可执行bootJar文件。 注意:如果需要将多个模块打包成一个可执行jar包,可以在根目录下的build.gradle文件中添加以下代码: ```groovy task fatJar(type: Jar) { manifest { attributes 'Main-Class': 'com.example.Application' } baseName = "${rootProject.name}-all" version = "${rootProject.version}" from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } with jar } ``` 其中,`com.example.Application`为启动类的全限定名。执行`./gradlew fatJar`命令即可在根目录下生成一个可执行jar包
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

挥之以墨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值