簡介
之前的文章我們講到了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 plugin
Enter selection (default: basic) [1..4] 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
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.0
Implementation-Title: lib
Implementation-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 filter
import org.apache.tools.ant.filters.ReplaceTokens
//for including in the copy task
def 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/
最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!