用Gradle构建Java项目示例

原文链接:Gradle官方文档

最终目标

建立一个java项目,其中包含一个主application和若干个library。

准备工作

  • 文本编辑器或IDE
  • JDK 1.8及以上
  • 最新的Gradle

创建项目文件夹

Gradle 带有一个名为 init 的内置任务,它会在一个空文件夹中初始化一个新的 Gradle 项目。init任务利用wrapper任务来创建Gradle wrpper脚本,即gradlew。

所以首先为新项目创建一个文件夹并且进入到文件夹中。

$ mkdir demo
$ cd demo

执行init任务

正如刚才所说的,执行init任务,如下:

$ gradle init

Select type of project to generate:
  1: basic
  2: application
  3: library
  4: Gradle plugin
Enter selection (default: basic) [1..4] 2

Split functionality across multiple subprojects?:
   1: no - only one application project
   2: yes - application and library projects
Enter selection (default: no - only one application project) [1..2] 2

Select implementation language:
  1: C++
  2: Groovy
  3: Java
  4: Kotlin
  5: Scala
  6: Swift
Enter selection (default: Java) [1..6] 3

Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 1

Select test framework:
  1: JUnit 4
  2: TestNG
  3: Spock
  4: JUnit Jupiter
Enter selection (default: JUnit 4) [1..4]

Project name (default: demo):
Source package (default: demo):


BUILD SUCCESSFUL
2 actionable tasks: 2 executed

init命令将会为你生成一个如下的项目:

├── gradle 
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew 
├── gradlew.bat 
├── settings.gradle 
├── buildSrc
│   ├── build.gradle 
│   └── src
│       └── main
│           └── groovy 
│               ├── demo.java-application-conventions.gradle
│               ├── demo.java-common-conventions.gradle
│               └── demo.java-library-conventions.gradle
├── app
│   ├── build.gradle 
│   └── src
│       ├── main 
│       │   └── java
│       │       └── demo
│       │           └── app
│       │               ├── App.java
│       │               └── MessageUtils.java
│       └── test 
│           └── java
│               └── demo
│                   └── app
│                       └── MessageUtilsTest.java
├── list
│   ├── build.gradle 
│   └── src
│       ├── main 
│       │   └── java
│       │       └── demo
│       │           └── list
│       │               └── LinkedList.java
│       └── test 
│           └── java
│               └── demo
│                   └── list
│                       └── LinkedListTest.java
└── utilities
    ├── build.gradle 
    └── src
        └── main 
            └── java
                └── demo
                    └── utilities
                        ├── JoinUtils.java
                        ├── SplitUtils.java
                        └── StringUtils.java

跟着文件夹目录,从上往下来看:

  1. gradle: 为gradle wrapper生成的文件夹

  2. gradlew/gradlew.bat : 启动gradle wrapper的脚本

  3. settings.gradle: 项目配置文件,用来定义构建名和子项目

    跟着下面就是四个项目目录buildSrc,app,list,utilities。buildSrc比较特殊,app是主application,list和utilities是library。

    buildSrc : 这个目录比较特殊,Gradle项目如发现项目中有这个目录,就会优先去编译并执行这个目录里面的项目代码,编译后的jar包可供gradle脚本使用。所以这个里面一般放些公共的插件,官方称其为:convention plugins【约定插件】


  4. buildSrc-build.gradle: buildSrc 的构建脚本,用于配置构建逻辑的依赖关系

  5. buildSrc-src-main: convention plugins【约定插件】内容,用 Groovy 或 Kotlin DSL编写。【其实也可以用Java】

  6. 其他三个项目目录下的build.gradle : 每个项目自己的构建脚本。

  7. 其他三个项目目录下的src-main : 每个项目自己的source文件夹。

项目文件介绍

先看根目录下的settings.gradle:

rootProject.name = 'demo'
include('app', 'list', 'utilities')

项目名 和 包含的子项目,这里并没有写buildSrc,因为buildSrc是gradle自动识别的,你叫其他名字都不好使。

因为这是个多项目工程,它的构建过程中可能会需要一些公共的逻辑和配置,所以我们使用了一个叫 convention plugins【约定插件】的东西,也就是buildSrc项目,让我们更方便的公用一些可重用的配置。

在这个示例中,我们可以找到三个这样的基于彼此的convention plugins【约定插件】:

buildSrc/src/main/groovy/demo.java-common-conventions.gradle

plugins {
    id 'java' 
}

repositories {
    mavenCentral() 
}

dependencies {
    constraints {
        implementation 'org.apache.commons:commons-text:1.9' 
    }

    testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1' 
}

tasks.named('test') {
    useJUnitPlatform() 
}

该文件定义了一些配置,这些配置我们整个Java工程都用得到,不管是application还是library。首先,构建Java项目,我们必须引入java插件,用 Java Plugin方法引入即可。然后我们为需要引入的外部依赖声明了仓库【mavenCentral()】,用repositories 方法声明。constraints 【约束】了标准的依赖,也就是项目中所有地方都能用到,和测试依赖,只有在测试代码中用得到。

其他共享设置,如编译器标志或 JVM 版本兼容性,也可以在这里设置。

再看另外两个:

buildSrc/src/main/groovy/demo.java-library-conventions.gradle

plugins {
    id 'demo.java-common-conventions' 

    id 'java-library' 
}
Groovy``Kotlin

buildSrc/src/main/groovy/demo.java-application-conventions.gradle

plugins {
    id 'demo.java-common-conventions' 

    id 'application' 
}

他们都引入了demo.java-common-conventions插件,以便在那里执行的配置由library和application项目共享。跟着他们分别应用 java-library 或application插件,从而将我们的通用配置逻辑与library或application的分别结合起来。

虽然在这个例子中没有更细粒度的配置,库或应用程序项目特定的构建配置可以进入这些约定插件脚本之一。

让我们看看子项目中的 build.gradle(.kts) 文件。

app/build.gradle

plugins {
    id 'demo.java-application-conventions'
}

dependencies {
    implementation 'org.apache.commons:commons-text'
    implementation project(':utilities')
}

application {
    mainClass = 'demo.app.App' 
}
Groovy``Kotlin

list/build.gradle

plugins {
    id 'demo.java-library-conventions'
}
Groovy``Kotlin

utilities/build.gradle

plugins {
    id 'demo.java-library-conventions'
}

dependencies {
    api project(':list')
}

查看构建脚本,我们可以看到它们最多包含三个块:

每个构建脚本都应该有一个 plugins {} 块来应用插件。在结构良好的构建中,它可能只应用一个约定插件,如本例所示。然后利用convention plugins【约定插件】来指定不同的细节。

其次,如果项目有依赖项,则应添加一个 dependencies {} 块。依赖可以是外部的,比如我们在java-common-conventions中添加的JUnit依赖,也可以指向其他本地子项目,本地子项目用Project()方法引入。在我们的示例中,utilities 库需要list 库,而app用到了utilities 库,如果本地项目相互依赖,Gradle (仅)会在需要时负责构建相关项目。

第三,插件可能有一个或多个配置块,如果它们为一个项目配置了一些特定的东西,那么它们只应该在构建脚本中直接使用。否则就应该写到convention plugins【约定插件】中去。在此示例中,我们使用特定于应用程序插件的 application {} 块将我们的应用程序项目中的 mainClass 设置为 demo.app.App 。

我们最后要看的是buildSrc中的build.gradle。

buildSrc/build.gradle

plugins {
    id 'groovy-gradle-plugin' 
}

repositories {
    gradlePluginPortal() 
}

buildSrc作为一个项目也可以指定插件和仓库,通过指定groovy-gradle-plugin或者 kotlin-dsl,我们支持在buildSrc中编写约定插件,当作构建文件。

执行application

借助application插件,您可以直接从命令行运行应用程序。run 任务告诉 Gradle 执行分配给 mainClass 属性的类中的 main 方法。

$ ./gradlew run

> Task :app:run
Hello world!

BUILD SUCCESSFUL
2 actionable tasks: 2 executed

打包项目

application插件也支持打包项目以及项目包含的所有依赖。打包的文件中还将包含一个脚本,用于使用单个命令启动应用程序。

$ ./gradlew build

BUILD SUCCESSFUL in 0s
7 actionable tasks: 7 executed

上述命令执行完后,Gradle会生成两种打包类型:xx.jar和xx.zip。

发布构建扫描

了解更多关于你的构建在幕后做什么的最好方法是发布构建扫描。为此,只需使用 --scan 标志运行 Gradle。

总结

That's it!您现在已经使用 Gradle 成功配置并构建了一个 Java 应用程序项目。您应该已经学会了:

  • 初始化一个生成 Java 应用程序的项目
  • 通过组合多个子项目创建模块化软件项目
  • 使用 buildSrc 中的约定插件在子项目之间共享构建配置逻辑
  • 在所有子项目中运行类似的命名任务
  • 在特定子项目中运行任务
  • 构建、打包和运行应用程序

进阶

当您的项目增长时,您可能会对如何配置 JVM 项目、构建多项目构建和依赖项管理的更多详细信息感兴趣:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容