Gradle jvm插件系列教程之Java?Library插件權(quán)威詳解
【Gradle jvm插件系列4】 Java Library插件用法示例權(quán)威詳解
使用方法
要使用Java Library插件,請(qǐng)?jiān)跇?gòu)建腳本中包含以下內(nèi)容:
plugins { id 'java-library' }
API和實(shí)現(xiàn)分離
標(biāo)準(zhǔn)Java插件和Java Library插件之間的關(guān)鍵區(qū)別在于后者引入了向消費(fèi)者公開的API概念。Java庫(kù)是供其他組件消費(fèi)的Java組件。在多項(xiàng)目構(gòu)建中這是非常常見的用例,也適用于外部依賴。
該插件公開了兩個(gè)配置,用于聲明依賴項(xiàng):api和implementation。api配置應(yīng)該用于聲明由庫(kù)API導(dǎo)出的依賴項(xiàng),而implementation配置應(yīng)該用于聲明組件內(nèi)部的依賴項(xiàng)。
示例2:聲明API和實(shí)現(xiàn)依賴項(xiàng)
dependencies { api 'org.apache.httpcomponents:httpclient:4.5.7' implementation 'org.apache.commons:commons-lang3:3.5' }
在api配置中聲明的依賴項(xiàng)將傳遞給庫(kù)的消費(fèi)者,因此將出現(xiàn)在消費(fèi)者的編譯類路徑上。而在implementation配置中聲明的依賴項(xiàng)則不會(huì)向消費(fèi)者公開,因此也不會(huì)出現(xiàn)在消費(fèi)者的編譯類路徑上。這樣做有以下幾個(gè)好處:
- 依賴項(xiàng)不會(huì)意外泄露到消費(fèi)者的編譯類路徑上,因此您永遠(yuǎn)不會(huì)意外依賴于傳遞性依賴項(xiàng)。
- 編譯速度更快,因?yàn)轭惵窂礁 ?/li>
- 當(dāng)實(shí)現(xiàn)依賴項(xiàng)發(fā)生變化時(shí),重新編譯次數(shù)較少:消費(fèi)者無(wú)需重新編譯。
- 發(fā)布更干凈:與新的maven-publish插件一起使用時(shí),Java庫(kù)會(huì)生成POM文件,明確區(qū)分針對(duì)庫(kù)的編譯所需和運(yùn)行時(shí)所需(換句話說(shuō),不要混淆用于編譯庫(kù)本身和用于針對(duì)庫(kù)編譯的內(nèi)容)。
Gradle 7.0版本已刪除了compile和runtime配置,請(qǐng)參考升級(jí)指南以了解如何遷移到implementation和api配置。
如果構(gòu)建使用具有POM元數(shù)據(jù)的發(fā)布模塊,則Java和Java Library插件都通過(guò)POM中使用的作用域來(lái)支持API和實(shí)現(xiàn)分離。這意味著編譯類路徑僅包括Maven compile范圍的依賴項(xiàng),而運(yùn)行時(shí)類路徑還包括Maven runtime范圍的依賴項(xiàng)。
這通常對(duì)于使用Maven發(fā)布的模塊沒有影響,因?yàn)槎x項(xiàng)目的POM文件直接作為元數(shù)據(jù)發(fā)布。在這種情況下,編譯范圍包括既用于編譯項(xiàng)目的依賴項(xiàng)(即實(shí)現(xiàn)依賴項(xiàng)),也用于針對(duì)已發(fā)布庫(kù)進(jìn)行編譯的依賴項(xiàng)(即API依賴項(xiàng))。對(duì)于大多數(shù)已發(fā)布的庫(kù)來(lái)說(shuō),這意味著所有依賴項(xiàng)都屬于編譯范圍。如果您在現(xiàn)有庫(kù)中遇到此類問(wèn)題,請(qǐng)考慮使用組件元數(shù)據(jù)規(guī)則來(lái)修復(fù)構(gòu)建中的錯(cuò)誤元數(shù)據(jù)。但是,如上所述,如果使用Gradle發(fā)布庫(kù),則生成的POM文件將api依賴項(xiàng)放入compile范圍,將其余的implementation依賴項(xiàng)放入runtime范圍。
如果構(gòu)建使用具有Ivy元數(shù)據(jù)的模塊,并且所有模塊都遵循特定結(jié)構(gòu),則可以按照此處描述的方式激活api和implementation分離。
從Gradle 5.0版本開始,默認(rèn)情況下啟用了模塊的編譯和運(yùn)行時(shí)范圍分離。從Gradle 4.6版本開始,您需要通過(guò)在settings.gradle中添加enableFeaturePreview('IMPROVED_POM_SUPPORT')
來(lái)激活它。
識(shí)別API和實(shí)現(xiàn)依賴項(xiàng)
本節(jié)將幫助您使用一些簡(jiǎn)單的經(jīng)驗(yàn)法則來(lái)識(shí)別代碼中的API和實(shí)現(xiàn)依賴項(xiàng)。首先的法則是:
在可能的情況下,優(yōu)先使用implementation配置。
這樣可以將依賴項(xiàng)保持在消費(fèi)者的編譯類路徑之外。此外,如果任何實(shí)現(xiàn)類型意外泄漏到公共API中,消費(fèi)者將立即無(wú)法編譯。
那么什么時(shí)候應(yīng)該使用api配置呢?API依賴項(xiàng)是至少包含一個(gè)在庫(kù)二進(jìn)制接口(ABI)中公開的類型的依賴項(xiàng)。這包括但不限于以下內(nèi)容:
- 用于超類或接口的類型
- 用于公共方法參數(shù)的類型,包括泛型參數(shù)類型(其中“公共”是對(duì)編譯器可見的內(nèi)容。即Java世界中的public、protected和package-private成員)
- 用于公共字段的類型
- 公共注解類型
相反,在以下列表中使用的任何類型都與ABI無(wú)關(guān),因此應(yīng)將其聲明為實(shí)現(xiàn)依賴項(xiàng):
- 僅在方法體中使用的類型
- 僅在私有成員中使用的類型
- 僅在內(nèi)部類中找到的類型(Gradle的未來(lái)版本將允許您聲明哪些包屬于公共API)
下面的示例代碼使用了一些第三方庫(kù),其中一個(gè)庫(kù)在類的公共API中暴露,另一個(gè)庫(kù)只在內(nèi)部使用。import語(yǔ)句無(wú)法幫助我們確定哪個(gè)是API依賴項(xiàng),因此我們必須查看字段、構(gòu)造函數(shù)和方法:
// The following types can appear anywhere in the code // but say nothing about API or implementation usage import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; public class HttpClientWrapper { private final HttpClient client; // private member: implementation details // HttpClient is used as a parameter of a public method // so "leaks" into the public API of this component public HttpClientWrapper(HttpClient client) { this.client = client; } // public methods belongs to your API public byte[] doRawGet(String url) { HttpGet request = new HttpGet(url); try { HttpEntity entity = doGet(request); ByteArrayOutputStream baos = new ByteArrayOutputStream(); entity.writeTo(baos); return baos.toByteArray(); } catch (Exception e) { ExceptionUtils.rethrow(e); // this dependency is internal only } finally { request.releaseConnection(); } return null; } // HttpGet and HttpEntity are used in a private method, so they don't belong to the API private HttpEntity doGet(HttpGet get) throws Exception { HttpResponse response = client.execute(get); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { System.err.println("Method failed: " + response.getStatusLine()); } return response.getEntity(); } }
HttpClientWrapper的公共構(gòu)造函數(shù)使用HttpClient作為參數(shù),因此它對(duì)消費(fèi)者可見,因此屬于API。請(qǐng)注意,HttpGet和HttpEntity在私有方法的簽名中使用,因此它們不計(jì)入使HttpClient成為API依賴項(xiàng)。
另一方面,來(lái)自commons-lang庫(kù)的ExceptionUtils類型僅在方法體中使用(而不是在其簽名中),因此它是實(shí)現(xiàn)依賴項(xiàng)。
因此,我們可以推斷httpclient是一個(gè)API依賴項(xiàng),而commons-lang是一個(gè)實(shí)現(xiàn)依賴項(xiàng)。這個(gè)結(jié)論可以轉(zhuǎn)化為構(gòu)建腳本中的以下聲明:
dependencies { api 'org.apache.httpcomponents:httpclient:4.5.7' implementation 'org.apache.commons:commons-lang3:3.5' }
Java Library插件配置
下面的圖表描述了在使用Java Library插件時(shí)如何設(shè)置配置。
綠色配置是用戶應(yīng)該用于聲明依賴關(guān)系的配置。
粉色配置是組件在編譯或與庫(kù)運(yùn)行時(shí)使用的配置。
藍(lán)色配置是組件內(nèi)部使用的配置,僅供其自身使用。
下一個(gè)圖表描述了測(cè)試配置的設(shè)置:
下表描述了每個(gè)配置的作用:
表格1. Java Library插件 - 用于聲明依賴關(guān)系的配置
配置名稱 | 作用 | 可消耗性 | 可解析性 | 描述 |
---|---|---|---|---|
api | 聲明API依賴關(guān)系 | 否 | 否 | 在這里聲明傳遞導(dǎo)出到消費(fèi)者的依賴關(guān)系,用于編譯時(shí)和運(yùn)行時(shí)。 |
implementation | 聲明實(shí)現(xiàn)依賴關(guān)系 | 否 | 否 | 在這里聲明純粹為內(nèi)部使用而不打算向消費(fèi)者公開的依賴關(guān)系(在運(yùn)行時(shí)仍然對(duì)消費(fèi)者公開)。 |
compileOnly | 聲明僅編譯依賴關(guān)系 | 否 | 否 | 在這里聲明在編譯時(shí)需要但在運(yùn)行時(shí)不需要的依賴關(guān)系。這通常包括在運(yùn)行時(shí)找到時(shí)會(huì)被屏蔽的依賴關(guān)系。 |
compileOnlyApi | 聲明僅編譯API依賴關(guān)系 | 否 | 否 | 在這里聲明模塊和消費(fèi)者在編譯時(shí)需要但在運(yùn)行時(shí)不需要的依賴關(guān)系。這通常包括在運(yùn)行時(shí)找到時(shí)會(huì)被屏蔽的依賴關(guān)系。 |
runtimeOnly | 聲明運(yùn)行時(shí)依賴關(guān)系 | 否 | 否 | 在這里聲明僅在運(yùn)行時(shí)需要而不在編譯時(shí)需要的依賴關(guān)系。 |
testImplementation | 測(cè)試依賴關(guān)系 | 否 | 否 | 在這里聲明用于編譯測(cè)試的依賴關(guān)系。 |
testCompileOnly | 聲明僅測(cè)試編譯依賴關(guān)系 | 否 | 否 | 在這里聲明僅在測(cè)試編譯時(shí)需要但不應(yīng)泄露到運(yùn)行時(shí)的依賴關(guān)系。這通常包括在運(yùn)行時(shí)找到時(shí)會(huì)被屏蔽的依賴關(guān)系。 |
testRuntimeOnly | 聲明測(cè)試運(yùn)行時(shí)依賴關(guān)系 | 否 | 否 | 在這里聲明僅在測(cè)試運(yùn)行時(shí)需要而不在測(cè)試編譯時(shí)需要的依賴關(guān)系。 |
表格2. Java Library插件 - 消費(fèi)者使用的配置
配置名稱 | 作用 | 可消耗性 | 可解析性 | 描述 |
---|---|---|---|---|
apiElements | 用于編譯此庫(kù) | 是 | 否 | 此配置用于供消費(fèi)者檢索編譯此庫(kù)所需的所有元素。 |
runtimeElements | 用于執(zhí)行此庫(kù) | 是 | 否 | 此配置用于供消費(fèi)者檢索運(yùn)行此庫(kù)所需的所有元素。 |
表格3. Java Library插件 - 庫(kù)本身使用的配置
配置名稱 | 作用 | 可消耗性 | 可解析性 | 描述 |
---|---|---|---|---|
compileClasspath | 用于編譯此庫(kù) | 否 | 是 | 此配置包含此庫(kù)的編譯類路徑,因此在調(diào)用Java編譯器進(jìn)行編譯時(shí)使用。 |
runtimeClasspath | 用于執(zhí)行此庫(kù) | 否 | 是 | 此配置包含此庫(kù)的運(yùn)行時(shí)類路徑。 |
testCompileClasspath | 用于編譯此庫(kù)的測(cè)試 | 否 | 是 | 此配置包含此庫(kù)的測(cè)試編譯類路徑。 |
testRuntimeClasspath | 用于執(zhí)行此庫(kù)的測(cè)試 | 否 | 是 | 此配置包含此庫(kù)的測(cè)試運(yùn)行時(shí)類路徑。 |
為Java模塊系統(tǒng)構(gòu)建模塊
自Java 9以來(lái),Java本身提供了一個(gè)模塊系統(tǒng),允許在編譯和運(yùn)行時(shí)進(jìn)行嚴(yán)格的封裝。您可以通過(guò)在main/java源文件夾中創(chuàng)建一個(gè)module-info.java文件將Java庫(kù)轉(zhuǎn)換為Java模塊。
src └── main └── java └── module-info.java
在module info文件中,您聲明一個(gè)模塊名稱,您希望導(dǎo)出哪些模塊包,并且您需要哪些其他模塊。
// module-info.java file module org.gradle.sample { requires com.google.gson; // real module requires org.apache.commons.lang3; // automatic module // commons-cli-1.4.jar is not a module and cannot be required }
為了告訴Java編譯器一個(gè)Jar是一個(gè)模塊,而不是傳統(tǒng)的Java庫(kù),Gradle需要將其放置在所謂的模塊路徑上。這是與classpath相反的一種選擇,classpath是告訴編譯器關(guān)于已編譯依賴關(guān)系的傳統(tǒng)方式。如果以下三個(gè)條件為真,Gradle將自動(dòng)將您的依賴項(xiàng)的Jar放置在模塊路徑上,而不是在classpath上:
java.modularity.inferModulePath
沒有被關(guān)閉- 我們實(shí)際上正在構(gòu)建一個(gè)模塊(而不是傳統(tǒng)的庫(kù)),這是通過(guò)添加
module-info.java
文件來(lái)表達(dá)的。 (另一種選擇是根據(jù)后面描述的Automatic-Module-Name Jar清單屬性添加。) - 我們的模塊依賴于的Jar本身是一個(gè)模塊,Gradle根據(jù)Jar中是否存在module-info.class(模塊描述符的編譯版本)來(lái)決定。 (或者,Jar清單中存在Automatic-Module-Name屬性)
接下來(lái),介紹一些關(guān)于定義Java模塊和與Gradle的依賴管理交互的更多詳細(xì)信息。您還可以查看一個(gè)現(xiàn)成的示例來(lái)直接嘗試Java模塊支持。
聲明模塊依賴關(guān)系
在構(gòu)建文件中聲明的依賴關(guān)系和在module-info.java文件中聲明的模塊依賴關(guān)系之間存在直接關(guān)系。理想情況下,這些聲明應(yīng)該保持同步,如下表所示:
Java模塊指令 | Gradle配置 | 目的 |
---|---|---|
requires | implementation | 聲明實(shí)現(xiàn)依賴關(guān)系 |
requires transitive | api | 聲明API依賴關(guān)系 |
requires static | compileOnly | 聲明僅編譯依賴關(guān)系 |
requires static transitive | compileOnlyApi | 聲明僅編譯API依賴關(guān)系 |
目前,Gradle不會(huì)自動(dòng)檢查依賴關(guān)系的聲明是否同步。這可能會(huì)在未來(lái)的版本中添加。
有關(guān)聲明模塊依賴關(guān)系的更多詳細(xì)信息,請(qǐng)參閱Java模塊系統(tǒng)的文檔。
聲明包可見性和服務(wù)
Java模塊系統(tǒng)支持比Gradle本身目前支持的更精細(xì)的封裝概念。例如,您需要明確聲明哪些包屬于您的API,哪些包只在模塊內(nèi)部可見。Gradle未來(lái)的版本可能會(huì)添加其中一些功能。現(xiàn)在,請(qǐng)參閱Java模塊系統(tǒng)的文檔,了解如何在Java模塊中使用這些特性。
聲明模塊版本
Java模塊也有一個(gè)版本,它作為module-info.class文件中模塊標(biāo)識(shí)的一部分進(jìn)行編碼。當(dāng)模塊運(yùn)行時(shí),可以檢查此版本。
// 示例:在構(gòu)建腳本中聲明模塊版本或直接作為編譯任務(wù)選項(xiàng) build.gradle version = '1.2' tasks.named('compileJava') { // 使用項(xiàng)目的版本或直接定義一個(gè)版本 options.javaModuleVersion = provider { version } }
使用非模塊化的庫(kù)
您可能希望在模塊化的Java項(xiàng)目中使用外部庫(kù),例如Maven Central中的OSS庫(kù)。一些庫(kù)在其較新版本中已經(jīng)是具有模塊描述符的完整模塊。例如,com.google.code.gson:gson:2.8.9具有模塊名稱com.google.gson。
其他庫(kù),例如org.apache.commons:commons-lang3:3.10,可能沒有提供完整的模塊描述符,但至少會(huì)在其清單文件中包含一個(gè)Automatic-Module-Name條目來(lái)定義模塊的名稱(示例中為org.apache.commons.lang3)。這樣的模塊,只有一個(gè)模塊名稱作為模塊描述,被稱為自動(dòng)模塊,它導(dǎo)出所有其包并可以讀取模塊路徑上的所有模塊。
第三種情況是不提供任何模塊信息的傳統(tǒng)庫(kù),例如commons-cli:commons-cli:1.4。Gradle將此類庫(kù)放置在類路徑上而不是模塊路徑上。對(duì)于Java來(lái)說(shuō),類路徑被視為一個(gè)模塊(稱為未命名模塊)。
// 示例:構(gòu)建文件中聲明的模塊和庫(kù)的依賴關(guān)系 build.gradle dependencies { implementation 'com.google.code.gson:gson:2.8.9' // real module implementation 'org.apache.commons:commons-lang3:3.10' // automatic module implementation 'commons-cli:commons-cli:1.4' // plain library }
// 在module-info.java文件中聲明的模塊依賴關(guān)系 module org.gradle.sample.lib { requires com.google.gson; // real module requires org.apache.commons.lang3; // automatic module // commons-cli-1.4.jar is not a module and cannot be required }
雖然真正的模塊不能直接依賴于未命名模塊(只能通過(guò)添加命令行標(biāo)志),但自動(dòng)模塊也可以看到未命名模塊。因此,如果您無(wú)法避免依賴于沒有模塊信息的庫(kù),您可以將該庫(kù)包裝在一個(gè)自動(dòng)模塊中作為項(xiàng)目的一部分。如何執(zhí)行這個(gè)操作在下一節(jié)中描述。
處理非模塊化的方式之一是使用artifact transforms自己向現(xiàn)有的Jars添加模塊描述符。該示例包含一個(gè)小的buildSrc插件,用于注冊(cè)這樣的轉(zhuǎn)換器,您可以使用并根據(jù)需要進(jìn)行調(diào)整。如果您想構(gòu)建一個(gè)完全模塊化的應(yīng)用程序,并希望Java運(yùn)行時(shí)將所有內(nèi)容視為真正的模塊,則可能會(huì)對(duì)此感興趣。
禁用Java模塊支持
在極少數(shù)情況下,您可能希望禁用內(nèi)置的Java模塊支持,并通過(guò)其他方式定義模塊路徑。為了實(shí)現(xiàn)這一點(diǎn),您可以禁用自動(dòng)將任何Jar放置在模塊路徑上的功能。然后,即使在源集中具有module-info.java,Gradle也會(huì)將帶有模塊信息的Jars放置在類路徑上。這對(duì)應(yīng)于Gradle版本<7.0的行為。
要使其工作,您需要在Java擴(kuò)展上(對(duì)于所有任務(wù))或個(gè)別任務(wù)上設(shè)置 modularity.inferModulePath = false
。
// 示例:禁用Gradle的模塊路徑推斷 build.gradle java { modularity.inferModulePath = false } tasks.named('compileJava') { modularity.inferModulePath = false }
構(gòu)建自動(dòng)模塊
如果可以的話,您應(yīng)該始終為您的模塊編寫完整的module-info.java描述符。但是,有一些情況下,您可能考慮(最初)只為自動(dòng)模塊提供模塊名稱:
- 您正在開發(fā)一個(gè)不是模塊的庫(kù),但是您希望在下一個(gè)版本中將其用作模塊。添加Automatic-Module-Name是一個(gè)很好的第一步(Maven中央的大多數(shù)熱門OSS庫(kù)現(xiàn)在已經(jīng)這樣做了)。
- 如前一節(jié)所討論的,自動(dòng)模塊可以用作真正模塊和類路徑上的傳統(tǒng)庫(kù)之間的適配器。
要將普通Java項(xiàng)目轉(zhuǎn)換為自動(dòng)模塊,只需添加具有模塊名稱的清單條目:
// 示例:在Jar清單屬性中聲明自動(dòng)模塊名稱 build.gradle tasks.named('jar') { manifest { attributes('Automatic-Module-Name': 'org.gradle.sample') } }
您可以將自動(dòng)模塊定義為多項(xiàng)目的一部分,該項(xiàng)目還定義了真正的模塊(例如,作為與另一個(gè)庫(kù)的適配器)。盡管Gradle構(gòu)建中的這種方式運(yùn)行良好,但I(xiàn)DEA / Eclipse當(dāng)前無(wú)法正確識(shí)別此類自動(dòng)模塊項(xiàng)目。您可以通過(guò)在IDE的UI中手動(dòng)將為自動(dòng)模塊構(gòu)建的Jar添加到無(wú)法找到它的項(xiàng)目的依賴項(xiàng)中來(lái)解決此問(wèn)題。
使用類而不是jar進(jìn)行編譯
java-library插件的一個(gè)特性是,消費(fèi)該庫(kù)的項(xiàng)目在編譯時(shí)只需要classes文件夾,而不需要完整的JAR文件。這樣可以實(shí)現(xiàn)更輕量級(jí)的項(xiàng)目間依賴,因?yàn)橹挥性陂_發(fā)過(guò)程中執(zhí)行Java代碼編譯時(shí)才會(huì)執(zhí)行資源處理(processResources任務(wù))和歸檔構(gòu)建(jar任務(wù))。
使用classes輸出而不是JAR是由消費(fèi)者決定的。例如,Groovy消費(fèi)者可能會(huì)請(qǐng)求classes和已處理的資源,因?yàn)檫@些可能在編譯過(guò)程中執(zhí)行AST轉(zhuǎn)換所需。
消費(fèi)者的內(nèi)存使用增加
一個(gè)間接的后果是,增量檢查將需要更多的內(nèi)存,因?yàn)镚radle將對(duì)單個(gè)類文件進(jìn)行快照,而不是單個(gè)jar文件。這可能會(huì)導(dǎo)致大型項(xiàng)目的內(nèi)存消耗增加,在某些情況下(例如,更改資源不再更改上游項(xiàng)目的compileJava任務(wù)的輸入),使得compileJava任務(wù)更容易處于最新狀態(tài)。
對(duì)于龐大的多項(xiàng)目,Windows系統(tǒng)會(huì)出現(xiàn)顯著的構(gòu)建性能下降
對(duì)于快照處理的單個(gè)類文件,僅影響Windows系統(tǒng),當(dāng)處理大量類文件時(shí),性能可能顯著下降。這僅涉及非常大的多項(xiàng)目,其中通過(guò)使用許多api或(已棄用的)compile依賴項(xiàng)在類路徑上存在許多類。為了緩解這個(gè)問(wèn)題,您可以將org.gradle.java.compile-classpath-packaging
系統(tǒng)屬性設(shè)置為true,以改變Java Library插件的行為,使用jar而不是class文件夾來(lái)處理編譯類路徑上的所有內(nèi)容。請(qǐng)注意,由于這會(huì)產(chǎn)生其他性能影響和潛在的副作用(通過(guò)觸發(fā)所有jar任務(wù)進(jìn)行編譯),只建議在Windows上遇到上述性能問(wèn)題時(shí)激活此選項(xiàng)。
發(fā)布庫(kù)
除了將庫(kù)發(fā)布到組件存儲(chǔ)庫(kù)外,有時(shí)您可能需要將庫(kù)及其依賴項(xiàng)打包到分發(fā)包中。Java Library Distribution插件就是為了幫助您完成這個(gè)任務(wù)。
參考鏈接
參考鏈接
小軍李:【Gradle jvm插件系列1】 Java Application插件權(quán)威詳解
小軍李:【Gradle jvm插件系列2】 Java Library插件用法示例權(quán)威詳解
小軍李:【Gradle jvm插件系列3】 Java platform平臺(tái)插件權(quán)威詳解
小軍李:【Gradle jvm插件系列4】 scala插件權(quán)威詳解
小軍李:【gradle多模塊系列1】多項(xiàng)目構(gòu)建和子項(xiàng)目的添加管理
小軍李:【Gradle多模塊系列2】在子項(xiàng)目之間聲明依賴關(guān)系和共享構(gòu)建邏輯示例詳解
小軍李:【Gradle 多模塊系列3】如何開發(fā)自定義Gradle插件
小軍李:【Gradle多模塊系列4】JVM項(xiàng)目的依賴管理
到此這篇關(guān)于Java Library插件權(quán)威詳解的文章就介紹到這了,更多相關(guān)Java Library插件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java并發(fā)編程之LongAdder執(zhí)行情況解析
這篇文章主要為大家介紹了Java并發(fā)編程之LongAdder執(zhí)行情況解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04Java中new Date().getTime()指定時(shí)區(qū)的時(shí)間戳問(wèn)題小結(jié)
本文主要介紹了Java中new Date().getTime()時(shí)間戳問(wèn)題小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07帶你輕松搞定Java面向?qū)ο蟮木幊?-數(shù)組,集合框架
Java是面向?qū)ο蟮母呒?jí)編程語(yǔ)言,類和對(duì)象是 Java程序的構(gòu)成核心。圍繞著Java類和Java對(duì)象,有三大基本特性:封裝是Java 類的編寫規(guī)范、繼承是類與類之間聯(lián)系的一種形式、而多態(tài)為系統(tǒng)組件或模塊之間解耦提供了解決方案2021-06-06Java數(shù)組的動(dòng)態(tài)初始化和常見問(wèn)題解析
本文介紹了數(shù)組動(dòng)態(tài)初始化的概念,即在初始化時(shí)僅指定數(shù)組長(zhǎng)度,系統(tǒng)會(huì)為數(shù)組分配初始值,而靜態(tài)初始化則手動(dòng)指定數(shù)組元素,系統(tǒng)根據(jù)元素個(gè)數(shù)計(jì)算數(shù)組長(zhǎng)度,這兩種初始化方式應(yīng)用場(chǎng)景不同,另外,還講述了數(shù)組默認(rèn)初始化值的規(guī)律及數(shù)組常見問(wèn)題,如越界問(wèn)題等2024-10-10guava中Multimap、HashMultimap用法小結(jié)
這篇文章主要介紹了guava中Multimap、HashMultimap使用,Multimap它可以很簡(jiǎn)單的實(shí)現(xiàn)一些功能,LinkedHashMultimap實(shí)現(xiàn)類與HashMultimap類的實(shí)現(xiàn)方法一樣,唯一的區(qū)別是LinkedHashMultimap保存了記錄的插入順序,本文就這些內(nèi)容講解的非常詳細(xì),需要的朋友參考下吧2022-05-05IDEA報(bào)錯(cuò):java:無(wú)效的源發(fā)行版21解決方式
這篇文章主要給大家介紹了關(guān)于IDEA報(bào)錯(cuò):java:無(wú)效的源發(fā)行版21的解決方式,這個(gè)錯(cuò)誤是因?yàn)槟愕捻?xiàng)目使用的Java版本與你的IDEA使用的Java版本不一致導(dǎo)致的,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06Java設(shè)計(jì)模式之外觀模式的實(shí)現(xiàn)方式
這篇文章主要介紹了Java設(shè)計(jì)模式之外觀模式的實(shí)現(xiàn)方式,外觀模式隱藏系統(tǒng)的復(fù)雜性,并向客戶端提供了一個(gè)客戶端可以訪問(wèn)系統(tǒng)的接口,這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它向現(xiàn)有的系統(tǒng)添加一個(gè)接口,來(lái)隱藏系統(tǒng)的復(fù)雜性,需要的朋友可以參考下2023-11-11