写点什么

在 gradle 中构建 java 项目

发布于: 2021 年 02 月 20 日

简介

之前的文章我们讲到了 gradle 的基本使用,使用 gradle 的最终目的就是为了构建 java 项目。今天本文将会详细的讲解如何在 gradle 中构建 java 项目。

构建 java 项目的两大插件

安装 java 项目的目的不同,构建 java 项目有两大插件,一个是 application,表示构建的是 java 应用程序;一个是 java-library,表示构建的是 java 库,供别的项目使用。

不管是构建应用程序还是 java 库,我们都可以很方便的使用 gradle init 来创新一个新的 gradle 项目:

$ gradle init
Select type of project to generate: 1: basic 2: application 3: library 4: Gradle pluginEnter selection (default: basic) [1..4] 2
Select implementation language: 1: C++ 2: Groovy 3: Java 4: Kotlin 5: Scala 6: SwiftEnter selection (default: Java) [1..6] 3
Select build script DSL: 1: Groovy 2: KotlinEnter selection (default: Groovy) [1..2] 1
Select test framework: 1: JUnit 4 2: TestNG 3: Spock 4: JUnit JupiterEnter selection (default: JUnit 4) [1..4]
Project name (default: demo):Source package (default: demo):

BUILD SUCCESSFUL2 actionable tasks: 2 executed
复制代码

application 和 library 的不同之处在于第二步选择的不同。

两者在 build.gradle 中的不同在于 plugins 的不同,application 的 plugin 是:

plugins {    id 'application' }
复制代码

而 library 的 plugin 是:

plugins {    id 'java-library' }
复制代码

还有一个不同之处是依赖的不同,先看一个 application 的依赖:

dependencies {    testImplementation 'junit:junit:4.13' 
implementation 'com.google.guava:guava:29.0-jre' }
复制代码

再看一个 library 的依赖:

dependencies {    testImplementation 'junit:junit:4.13' 
api 'org.apache.commons:commons-math3:3.6.1'
implementation 'com.google.guava:guava:29.0-jre' }
复制代码

因为 library 是需要给第三方应用程序使用的,所以这里多了一个 api 的使用,api 表示是第三方应用程序也需要依赖这个包,而 implementation 表示的是该包只是在这个项目内部被依赖。

在构建 libary 的时候,还可以自定义 manifest 的信息:

tasks.named('jar') {    manifest {        attributes('Implementation-Title': project.name,                   'Implementation-Version': project.version)    }}
复制代码

上面的例子将会在 META-INF/MANIFEST.MF 生成:

Manifest-Version: 1.0Implementation-Title: libImplementation-Version: 0.1.0
复制代码

我们还可以指定编译的 java 版本号和 lib 的版本:

java {    toolchain {        languageVersion = JavaLanguageVersion.of(11)    }}
version = '1.2.1'
复制代码

管理依赖

java 的依赖一般都是 jar 包组成的 library。和 maven 一样,我们在 gradle 中指定依赖需要指定依赖的名字和版本号,依赖的范围:是运行时依赖还是编译时依赖,还有一个重要的就是在哪里可以找到这个 library。

前面两个属性我们可以在 dependencies 中找到,后面一个我们可以在 repositories 中找到,看一个例子:

repositories {    mavenCentral()}
dependencies { implementation 'org.hibernate:hibernate-core:3.6.7.Final'}
复制代码

还可以使用这种形式的 maven:

repositories {    maven {        url "http://repo.mycompany.com/maven2"    }}
复制代码

或者 Ivy:

repositories {    ivy {        url "http://repo.mycompany.com/repo"    }}
复制代码

甚至可以使用本地的 local dir:

repositories {    flatDir {        dirs 'lib'    }    flatDir {        dirs 'lib1', 'lib2'    }}
复制代码

上面定义了一个 mavenCentral 的仓库,我们可以在这个仓库中去查找 hibernate-core 这个依赖的 jar 包。

在 dependencies 这一块,我们可以定义依赖包的工作范围:

  • compileOnly: 表示依赖包只被用来编译代码,并不用在程序的运行。

  • implementation:表示依赖包被用在编译和运行时。

  • runtimeOnly: 只在运行时使用。

  • testCompileOnly: 仅在 test 的编译时使用。

  • testImplementation:在 test 的编译和运行时使用。

  • testRuntimeOnly: 在 test 的运行时使用。

我们还可以添加动态的依赖:

dependencies {    implementation 'org.springframework:spring-web:5.+'}
复制代码

使用项目作为依赖:

dependencies {    implementation project(':shared')}
复制代码

编译代码

一般情况下你的源代码需要放在 src/main/java 目录下,测试代码需要放在 src/test/java 下面。然后添加 compileOnly 或者 implementation 依赖,如果需要测试的话,添加 testCompileOnly 或者 testImplementation 依赖。

然后就可以运行 compileJava 和 compileTestJava 来编译代码了。

当然,如果你有自定义的源文件目录,也可以这样手动指定:

sourceSets {    main {         java {            srcDirs = ['src']         }    }
test { java { srcDirs = ['test'] } }}
复制代码

上面的代码中我们给 srcDirs 重新赋值了。如果我们只是想要在现有的代码路径上再添加一个新的路径,那么可以使用 srcDir:

sourceSets {    main {        java {            srcDir 'thirdParty/src/main/java'        }    }}
复制代码

除了源代码的路径,我们还可以配置编译的参数,并指定编译的 JDK 版本号:

compileJava {    options.incremental = true    options.fork = true    options.failOnError = false    options.release = 7}
复制代码

注意,gradle 必须要在 JDK8 以上才能运行,但是我们可以指定 gradle 去使用 Java 6 或者 Java 7 去编译源代码。

我们还可以指定预览版本的特性:

tasks.withType(JavaCompile) {    options.compilerArgs += "--enable-preview"}tasks.withType(Test) {    jvmArgs += "--enable-preview"}tasks.withType(JavaExec) {    jvmArgs += "--enable-preview"}
复制代码

管理 resource

java 除了源代码文件之外,还有一些 resource 文件,比如配置文件,图片文件,语言文件等等。我们需要将这些配置文件拷贝到特定的目标目录中。

默认情况下,gradle 会拷贝 src/[sourceSet]/resources 中的文件到目标文件夹中。

我们看一个复杂的拷贝动作:

task copyDocs(type: Copy) {    from 'src/main/doc'    into 'build/target/doc'}
//for Ant filterimport org.apache.tools.ant.filters.ReplaceTokens
//for including in the copy taskdef dataContent = copySpec { from 'src/data' include '*.data'}
task initConfig(type: Copy) { from('src/main/config') { include '**/*.properties' include '**/*.xml' filter(ReplaceTokens, tokens: [version: '2.3.1']) } from('src/main/config') { exclude '**/*.properties', '**/*.xml' } from('src/main/languages') { rename 'EN_US_(.*)', '$1' } into 'build/target/config' exclude '**/*.bak'
includeEmptyDirs = false
with dataContent}
复制代码

打包和发布

我们可以根据不同的构建类型来打包对应的文件。比如对应 java lib 来说,我们可以同时上传源代码和 java doc 文件:

java {    withJavadocJar()    withSourcesJar()}
复制代码

比如说我们还可以打包成一个 fat jar 包:

plugins {    id 'java'}
version = '1.0.0'
repositories { mavenCentral()}
dependencies { implementation 'commons-io:commons-io:2.6'}
task uberJar(type: Jar) { archiveClassifier = 'uber'
from sourceSets.main.output
dependsOn configurations.runtimeClasspath from { configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { zipTree(it) } }}
复制代码

生成 javadoc

gradle 的 java library 插件有一个 javadoc task,可以为 java 项目生成文档。它支持标准的 javadoc,也支持其他类型的文档,比如说 Asciidoc,我们看一个生成 Asciidoc 的例子:

configurations {    asciidoclet}
dependencies { asciidoclet 'org.asciidoctor:asciidoclet:1.+'}
task configureJavadoc { doLast { javadoc { options.doclet = 'org.asciidoctor.Asciidoclet' options.docletpath = configurations.asciidoclet.files.toList() } }}
javadoc { dependsOn configureJavadoc}
复制代码

本文已收录于 http://www.flydean.com/gradle-build-java-projects/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!


发布于: 2021 年 02 月 20 日阅读数: 24
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020.06.07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
在gradle中构建java项目