在Java項目中,有兩個主要的構建系統:Gradle和Maven。構建系統主要管理潛在的複雜依賴關係並正確編譯項目。還能夠將已編譯的項目以及全部資源和源文件打包到.war
或.jar
文件中。對於簡單的構建,Maven和Gradle之間的選擇幾乎是我的喜愛之一,或者也許是公司CTO或技術經理的偏好。他們倆都是很是好的構建工具。可是,對於更復雜的項目,Gradle比Maven更勝一籌。java
我的喜歡Gradle;我討厭XML,複雜的Java/Groovy項目,若是沒有Gradle,幾乎是步履維艱的。除了沒有複雜的XML之外,Gradle還使用Groovy或Kotlin編寫的構建腳本提供了靈活性和更快的構建速度。藉助Kotlin或Groovy的所有功能以及Gradle API庫,您能夠建立功能強大且複雜的構建腳本。這確定是提高效率的工具。web
對於DSL(特定於域的語言)須要一些時間來適應,而且Gradle以難以學習而著稱。可是,我認爲這主要是由於人們已經習慣了Maven。使用Gradle,您實質上能夠學習一種構建語言,而不僅是簡單地學習XML。與僅在Maven中添加依賴項相比,充分利用Gradle無疑具備更陡峭的學習曲線。可是向Gradle文件添加依賴項實際上並不比在Maven中困難。擴展和自定義Gradle構建比編寫Maven插件和自定義構建步驟要簡單得多。spring
Gradle還極大地縮短了構建時間,尤爲是在大型項目中,由於Gradle僅處理已更改的任務和文件就能夠很好地完成工做。此外,它提供了構建緩存和構建守護進程,使重複構建的性能更高。並且,像Maven同樣,它使用並行線程進行依賴關係解析和項目構建。一樣,對於小型,簡單的構建,這種性能提高可能並不明顯。可是對於較大的項目,這種性能提高是巨大的。shell
所以,總結一下。Gradle是:apache
==
更陡峭的學習曲線而Maven是:編程
簡要介紹一下Groovy。Groovy是一種JVM語言,它能夠編譯爲與Java相同的字節碼,而且能夠與Java類無縫地互操做。Groovy是Java的向後兼容超集,這意味着Groovy能夠透明地與Java庫和代碼交互。可是,它還增長了許多新功能:可選的鍵入,函數式編程,運行時靈活性以及許多元編程內容。它還極大地清理了Java中許多冗長的代碼格式。Groovy還沒有成爲主流的開發語言,可是它已經在測試(因爲其簡化的語法和元編程功能)和構建系統中佔據了一席之地。api
您須要爲本教程安裝一些內容:緩存
Java:您可能已經安裝了Java。本教程至少須要Java 1.8。若是不是,請轉到官網下載並安裝它。springboot
Gradle:可是,因爲本教程是有關Gradle的教程,所以在本教程中,您能夠繼續進行安裝。數據結構
build.gradle
build.gradle
文件是Gradle項目的核心,是構建配置必不可少的一項。就好比pom.xml
對於Maven來講,這是等效的(沒有全部使人討厭的尖括號)
讓咱們來看一個。
// 配置運行構建腳本的要求 buildscript { // 設置自定義屬性 ext { springBootVersion = '2.1.6.RELEASE' } // 解決buildscript塊中的依賴項時,檢查Maven Central中的依賴項 repositories { mavenCentral() } // 咱們須要spring boot插件來運行構建腳本 dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } // 添加構建插件 apply plugin: 'java' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' // 設置全局變量 group = 'com.okta.springboottokenauth' version = '0.0.1-SNAPSHOT' sourceCompatibility = 1.8 // 用於搜索以解決項目依賴關係的倉庫地址 repositories { mavenCentral() } // 項目依賴 dependencies { implementation( 'com.okta.spring:okta-spring-boot-starter:1.2.1' ) implementation('org.springframework.boot:spring-boot-starter-security') implementation('org.springframework.boot:spring-boot-starter-web') testImplementation('org.springframework.boot:spring-boot-starter-test') testImplementation('org.springframework.security:spring-security-test') }
理解Gradle構建文件的關鍵是要意識到它是一個腳本,內置在Groovy DSL中。粗略地講,它是一個配置腳本,它調用定義了配置選項的一系列閉包(考慮函數)。它看起來像JSON或propertiy文件,儘管從技術上來講這是錯誤的。
可是,真正的有趣的來自build.gradle
Groovy腳本。由於它能夠執行任意代碼並訪問任何Java庫,特定於構建的Gradle DSL和Gradle API。
buildscript
讓咱們從上至下查看腳本:
buildscript
閉包配置構建腳本自己(與應用程序相對)所需的屬性,依賴項和源倉庫。apply plugin
以很是好友的方式應用了插件。這些擴展了Gradle-Groovy DSL框架的基本功能:將該java插件與Spring Boot和Spring依賴項管理一塊兒應用。Java插件提供配置Gradle的指望標準的Java項目的目錄結構:src/main/java
,src/main/resources
,src/test/java
等,這些能夠被配置爲改變默認的目錄或添加新的目錄。repositories
塊定義了構建腳本將在哪裏尋找依賴關係。Maven Central是最多見的(mavenCentral()
),但也能夠配置其餘倉庫,包括自定義倉庫和本地倉庫。可使用來將本地Maven緩存配置爲倉庫mavenLocal()
。若是團隊但願協調項目之間的構建,但又不想將項目構建文件實際捆綁在一塊兒,這將頗有幫助。其中每一個模塊定義閉包的順序可有可無,由於大多數build.gradle
文件僅定義依賴項,設置項目屬性並使用預約義的任務,所以文件中元素的順序可有可無。例如,沒有理由repositories
塊必須走在該dependencies
塊以前。您能夠將build.gradle
文件視爲Gradle在執行調用它的shell命令分配的任何任務以前讀取的配置文件。
可是,當您開始使用Gradle的功能來定義自定義任務並執行任意代碼時,它將變得更加複雜。Gradle將以build.gradle
自上而下的方式讀取文件,並執行在其中找到的全部代碼塊;根據此代碼的做用,它能夠在腳本中建立強制排序。此外,當您定義自定義任務和屬性(在Gradle API中找不到)時,排序很重要,由於這些符號不會被預先定義,所以必須在構建腳本中定義它們才能使用它們。
回到Groovy剛問世時,函數式編程是至關小衆的領域,將諸如閉包之類的東西帶入JVM感受很瘋狂。現在,它變得更加廣泛:Javascript中的每一個函數都是閉包。通常來講,閉包是具備範圍的一流函數。
這意味着兩件事:
Java版本的閉包稱爲lambda。這些是在1.8版中引入Java的,順便說一句,這並非在Groovy得到最初的流行和函數式編程開始發展的同時發生的。
爲了演示lambda,請看一下名爲的JUnit測試LambdaTest.java
。
src/test/java/com/okta/springboottokenauth/LambdaTest.java
interface SimpleLambda { public int sum(int x, int y); } public class LambdaTest { // 建立一個lambda函數 public SimpleLambda getTheLambda(int offset) { int scopedVar = offset; return (int x, int y) -> x + y + scopedVar; } @Test public void testClosure() { // 測試lambda方法,當offset=1 SimpleLambda lambda1 = getTheLambda(1); assertEquals(lambda1.sum(2,2), 5); // 測試lambda方法,當offset=2 SimpleLambda lambda2 = getTheLambda(2); assertEquals(lambda2.sum(2,2), 6); } }
這個示例頗有表明性,演示了lambda的兩個基本屬性。在閉包或lambda函數中,實現是在getTheLambda(int offset)
方法中定義的。建立lambda時,將offset變量封裝在閉包範圍中並返回。該lambda被分配給變量。能夠重複調用它,而且它將引用相同的做用域。此外,可使用封裝在單獨做用域中並分配給其餘變量的新變量來建立新的lambda。
來自強大的面向對象的背景,封閉最初感受就像蟲洞在嚴格的對象範圍連續體上打穿透孔同樣,奇怪地將對象的各個部分在空間和時間上鍊接在一塊兒。
採起build.gradle
文件的依賴項部分:
dependencies { implementation( 'com.okta.spring:okta-spring-boot-starter:1.2.1' ) implementation('org.springframework.boot:spring-boot-starter-security') ... }
沒有Groovy DSL速記,其實是:
project.dependencies({ implementation( 'com.okta.spring:okta-spring-boot-starter:1.2.1' ) implementation('org.springframework.boot:spring-boot-starter-security') ... })
括號中的全部內容實際上都是傳遞給該project.dependencies()
方法的閉包。該project
對象是Project
該類的實例,該類是構建的主要API父類。
如您所見,這些函數將一系列依賴項做爲字符串傳遞。那麼,爲何不使用更傳統的靜態數據結構(如JSON,屬性或XML)呢?緣由是這些重載函數也可使用閉包代碼塊,所以能夠進行深度自定義。
依賴關係塊內部是一系列配置和名稱。
dependencies { configurationName dependencyNotation }
咱們的build.gradle
文件使用兩種配置:implementation
和testImplementation
。
implementation()
定義編譯時所需的依賴項。此配置方法稱爲compile
。testImplementation()
並定義了僅用於測試(舊testCompile
)所需的依賴項。
您可能會看到的另外一個依賴項配置是runtimeOnly
和testRuntimeOnly
。這聲明瞭運行時提供的不須要對其進行編譯的依賴項。
定義依賴關係的方法比對本文的範圍有用的方法更多。幾乎能夠說任何東西均可以是依賴項:本地文件,jar的目錄,另外一個Gradle項目等等,而且能夠將依賴項配置爲執行某些操做,例如排除某些子依賴項。
值得注意的是:Gradle和Maven以徹底相同的方式解決依賴關係。例如,假設咱們想從Spring Boot Starter
中排除Log4j
依賴關係,咱們能夠這樣作:
dependencies { implementation( 'com.okta.spring:okta-spring-boot-starter:1.2.1' ) { exclude group: 'org.apache.logging.log4j', module: 'log4j-api' } }
或者說咱們想將目錄中的全部文件都包含libs
爲依賴項:
dependencies { implementation fileTree('libs') }
關於Gradle的一件很棒的事情是Gradle包裝器。Gradle命令行爲gradle
。可是,您會注意到在網上的許多地方,您都會看到./gradlew
或gradlew.bat
。這些是調用包裝程序的命令。
包裝器容許項目捆綁在項目自己內部構建項目所需的Gradle版本。這樣能夠確保對Gradle的更改不會中斷構建。它還能夠確保即便沒有安裝Gradle的人也能夠運行構建。
它將如下文件添加到您的項目:
├── gradle │ └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew └── gradlew.bat
gradlew
和gradlew.bat
是用於Linux/OSX和Window(分別)執行腳本。他們運行build.gradle
使用捆綁的搖籃文件.jar
的gradle/wrapper
子目錄。
任務是Gradle的核心。Java插件增長了十幾個任務,包括:clean
,compile
,test
,jar
,和uploadArchives
。Spring Boot插件添加了bootRun
任務,該任務運行Spring Boot應用程序。
一般,任務是這樣運行的:gradle taskName otherTaskName
,或使用包裝器:./gradlew taskName otherTaskName
。
若是打開終端並cd進入示例項目的基本目錄,則可使用gradle tasks
列出build.gradle
文件定義的全部任務。tasks
固然,它自己是由基本Gradle API定義的任務。
> Task :tasks ------------------------------------------------------------ Tasks runnable from root project ------------------------------------------------------------ Build tasks ----------- assemble - Assembles the outputs of this project. build - Assembles and tests this project. buildDependents - Assembles and tests this project and all projects that depend on it. buildNeeded - Assembles and tests this project and all projects it depends on. classes - Assembles main classes. clean - Deletes the build directory. jar - Assembles a jar archive containing the main classes. testClasses - Assembles test classes. Build Setup tasks ----------------- init - Initializes a new Gradle build. wrapper - Generates Gradle wrapper files. Distribution tasks ------------------ assembleDist - Assembles the main distributions assembleMonitorDist - Assembles the monitor distributions distTar - Bundles the project as a distribution. distZip - Bundles the project as a distribution. installDist - Installs the project as a distribution as-is. installMonitorDist - Installs the project as a distribution as-is. monitorDistTar - Bundles the project as a distribution. monitorDistZip - Bundles the project as a distribution. Documentation tasks ------------------- groovydoc - Generates Groovydoc API documentation for the main source code. javadoc - Generates Javadoc API documentation for the main source code. Help tasks ---------- buildEnvironment - Displays all buildscript dependencies declared in root project 'fun'. components - Displays the components produced by root project 'fun'. [incubating] dependencies - Displays all dependencies declared in root project 'fun'. dependencyInsight - Displays the insight into a specific dependency in root project 'fun'. dependentComponents - Displays the dependent components of components in root project 'fun'. [incubating] help - Displays a help message. model - Displays the configuration model of root project 'fun'. [incubating] projects - Displays the sub-projects of root project 'fun'. properties - Displays the properties of root project 'fun'. tasks - Displays the tasks runnable from root project 'fun'. IDE tasks --------- cleanIdea - Cleans IDEA project files (IML, IPR) idea - Generates IDEA project files (IML, IPR, IWS) openIdea - Opens the IDEA project Verification tasks ------------------ check - Runs all checks. test - Runs the unit tests. Rules ----- Pattern: clean<TaskName>: Cleans the output files of a task. Pattern: build<ConfigurationName>: Assembles the artifacts of a configuration. Pattern: upload<ConfigurationName>: Assembles and uploads the artifacts belonging to a configuration. To see all tasks and more detail, run gradle tasks --all To see more detail about a task, run gradle help --task <task>
我想指出dependencies
任務。它將列出一棵樹,其中包含項目所需的全部依賴關係(包括子依賴關係)。嘗試gradle dependencies
在項目根目錄中運行。您可使用該dependencyInsight
任務來深刻了解特定的子依賴項。
另外一個有助於解決問題的properties
任務是該任務,該任務列出了在根項目對象實例上定義的全部屬性。
固然,在開發Spring Boot項目時,可使用命令:./gradlew bootJar
,該任務將項目及其依賴項打包在一個jar文件中。
到此,基礎篇完事兒,提升篇中將會實踐一下自定義任務和Groovy閉包在Gradle配置文件build.gradle
文件中如何使用。