Gradle基礎學習(六) 認識任務Task

理解Gradle中的任務

Gradle的構建過程基于任務(Task)的概念,而每個任務都可以包含一個或多個動作(Action)。

任務是構建中執行的一些獨立的工作單元,例如編譯類、創建JAR、生成Javadoc或將存檔發布到倉庫。

我們使用gradle taskName或gradlew taskName來執行任務,比如build:

$ ./gradlew build?

項目中所有可用任務都是來自Gradle插件和構建腳本。

比如在子項目構建腳本中創建的任務:

可用任務清單

我們通過運行tasks任務來列出項目所有可用任務。

$ ./gradlew tasks

讓我們以一個非常基本的Gradle項目為例,該項目具有以下結構:

?settings.gradle.kts文件定義了根項目名稱和app子項目:

rootProject.name = "HelloGradle"

include("app")

目前app子項目的構建文件暫時是一個空文件。

為了看app子項目中的任務,運行./gradlew :app:tasks?

結果中只能看到少量的輔助任務(Help Tasks),它們是Gradle核心提供的用于分析構建的任務。其他任務,如構建項目或編譯代碼的任務,則是由插件來添加的。

我們接下來在app構建腳本里添加application插件:

//app/build.gradle.kts

plugins {

? ? id("application")

}

application插件會添加一些生命周期任務。 現在再運行./gradlew app:tasks,我們看到多了一些和構建相關的任務,比如assemble?和?build任務:

任務結果

當Gradle執行一個任務時,它會在控制臺中顯示任務的結果標簽。

這些標簽描述了一個任務是否有要執行的動作,Gradle是否執行了這些動作。動作包括但不限于編譯代碼、壓縮文件和發布存檔。

(no label)?or?EXECUTED

任務執行了動作。

任務有動作,Gradle執行了它們。

任務沒有動作,有一些依賴項,Gradle執行了一個或多個依賴項。

UP-TO-DATE

Gradle會檢查任務的輸入和輸出,如果輸入沒有變化,并且輸出已經存在且是最新的,那么任務就不會被執行,并標記為UP-TO-DATE。

任務有輸出和輸入,但都沒有改變。

任務有動作,但是告訴Gradle它不會改變輸出。

任務沒有動作,有一些依賴項,但所有依賴都是UP-TO-DATE,?SKIPPED?或?FROM-CACHE的。

任務沒有動作,也沒有任何依賴項。

FROM-CACHE

Gradle檢測到任務的輸出已經在構建緩存中時,會直接從緩存中加載,比如build cache。?

SKIPPED

任務不執行他的動作

任務被跳過可能是因為某個先決條件未滿足,或者任務被明確地配置為跳過,比如使用命令行選項--exclude-task排除。

NO_SOURCE

任務不需要執行他的動作

任務有輸入和輸出,但沒有源文件。

FROM-CACHE和UP-TO-DATE都是Gradle優化構建過程的手段,都有助于減少不必要的任務執行,提高構建速度。可能會弄不明白什么時候是UP-TO-DATE或者FROM-CACHE,在本文后面介紹緩存任務的時候,我們再做進一步說明。?

任務組group和描述description

任務組和描述用于組織和描述任務。

Groups

任務組被用來對任務進行分類,當運行./gradlew tasks時,所有任務會被列在各自的組中,這樣更容易理解它們的目的和與其他任務的關系,使用group屬性設置組。

Descriptions
描述提供了任務功能的簡要解釋。當運行./gradlew tasks時,描述會顯示在每個任務的旁邊,幫助開發者了解它的用途以及如何使用它,使用description屬性設置描述。

我們回頭去看一下前面gradle-project執行tasks的輸出結果:

:run任務屬于Application分組, 對其描述是 "Runs this project as a JVM application"。?

這個任務在代碼中的定義會像這樣:

//app/build.gradle.kts

tasks.register("run") {

? ? group = "Application"

? ? description = "Runs this project as a JVM application."

}

私有和隱藏任務

Gradle不支持將任務標記為“私有”。

當我們運行:tasks時,默認只會顯示那些分配了任務組的任務,即所謂的可見任務,而那些沒有分配group的任務,就是隱藏任務, 需要注意,隱藏任務依舊可以被Gradle執行,只是不顯示而已。

如下所示,我們創建了一個任務helloTask,執行./gradlew :app:tasks,任務列表里并沒有找到helloTask任務。

//app/build.gradle.kts

tasks.register("helloTask") {

? ? println("Hello")

}

給它分配一個group?

tasks.register("helloTask") {

? ? group = "Other"

? ? description = "Hello task"

? ? println("Hello")

}

任務就出現在了指定的Other分組下?:

執行./gradlew tasks --all 可以顯示所有任務,包括隱藏的。?

比如上面的helloHiddenTask,我們沒有設置group屬性,也顯示在了Other分組下。?

分組任務

如果我們想要自定義執行tasks時向用戶顯示哪些任務,可以對任務分組并設置每個組的可見性。

示例gradle-project雖然只是一個簡單的Java應用,列出的可用的任務卻非常多,使用構建的開發人員很少直接需要其中的許多任務。

我們可以通過配置tasks任務,限制任務顯示到一個特定的分組。

我們修改一下構建腳本,創建一個自己的分組,使用displayGroup屬性來指定要顯示的任務組。

//app/build.gradle.kts

val myBuildGroup = "my app build" ? ? ? ? ? ? ? // Create a group name

tasks.register<TaskReportTask>("tasksAll") {? ? // Register the tasksAll task

? ? group = myBuildGroup

? ? description = "Show additional tasks."

? ? setShowDetail(true)

? ? println("register tasksAll")

}

tasks.named<TaskReportTask>("tasks") {?

? ? displayGroup = myBuildGroup

}

在Gradle中,我們執行tasks任務時,會使用此類型的一個實例TaskReportTask,其中displayGroup屬性用來控制要顯示的任務組,默認值是null, 可以使用命令行選項 '--group'設置,設置后就只顯示這個分組的任務。

任務類別?

Gradle中的任務分為兩類:

1. Actionable tasks(可操作任務)

2. Lifecycle tasks(生命周期任務)

可執行任務定義了Gradle應該執行的具體操作。例如,:compileJava?任務,它編譯項目的Java代碼。這些操作包括創建JAR文件、壓縮文件、發布歸檔文件等。當你應用了一個插件,如java-library,Gradle會自動添加與該插件相關的可執行任務。

生命周期任務定義了一系列的目標(targets),你可以調用這些目標來執行一系列的操作。例如,:build?就是一個常見的生命周期任務,用于構建整個項目。這類任務本身不執行具體的操作(actions)。相反,它們捆綁了可執行任務,當調用生命周期任務時,會觸發與之關聯的可執行任務。 基礎Gradle插件(base Gradle plugin)只添加生命周期任務。這意味著如果你沒有添加任何插件,Gradle仍然會提供這些基本的生命周期任務。

我們再看一下之前例子的:tasks結果

如果我們執行:build任務,會看到有好幾個任務都被執行了,包括:app:compileJava任務。

可以表述為可執行任務:compileJava捆綁到了生命周期任務:build中。?

增量任務

Gradle任務的一個關鍵特征是它們的增量性。

Gradle可以重用之前構建的結果。因此,如果我們之前構建過項目,并且只進行了小幅更改,那么重新運行:build將不需要Gradle執行大量工作。

例如,如果我們只修改項目中的測試代碼,保持生產代碼不變,執行構建將僅重新編譯測試代碼。Gradle將生產代碼的任務標記為UP-TO-DATE,表明自上次成功構建以來,它保持不變:

緩存任務

Gradle可以使用構建緩存來重用過去構建的結果。

要啟用此功能,請使用--build-cache命令行參數或在gradle.properties文件中設置org.gradle.caching=true來激活構建緩存。

此優化有可能顯著加速項目的構建:

當Gradle可以從緩存中獲取一個任務的輸出時,它會給這個任務貼上FROM-CACHE的標簽。如果經常在分支之間切換,構建緩存很方便。Gradle支持本地和遠程構建緩存。

我們通過實際執行其中的compileJava源碼編譯任務來加深對任務結果為UP-TO-DATE和FROM-CACHE的理解:

我們把之前的gradle-project例子修改一下

//app/build.gradle.kts

//添加執行入口類

application {

? ? mainClass = "gradle.project.App"

}

//app/src/main/java/gradle/project/App.java

package gradle.project;

public class App {

? ? public static void main(String[] args) {

? ? ? ? System.out.println("Hello World!");

?? }

}

現在app子項目是一個可執行的Java 應用程序,App類是應用的執行入口。

先./gradlew clean刪除各子項目build目錄,確保項目是干凈的狀態。

執行compileJava任務編譯java,? --build-cache告訴Gradle本次使用構建緩存,需要--info選項顯示一些額外的構建信息:

./gradlew --build-cache compileJava --info

Settings evaluated using settings file '/Users/roy/Downloads/gradle-project/settings.gradle'.

Using local directory build cache for the root build (location = /Users/xxx/.gradle/caches/build-cache-1, removeUnusedEntriesAfter = 7 days).

Projects loaded. Root project using build file '/Users/xxx/Downloads/gradle-project/build.gradle'.

> Task :app:compileJava

Stored cache entry for task ':app:compileJava' with cache key db35214e1886f8b0ebbcc16e2fa7a618

BUILD SUCCESSFUL in 1s

1 actionable task: 1 executed

?執行成功后,app子項目里多了build目錄,輸出的信息里也看到了build cache目錄默認的位置Gradle User Home/caches/build-cache-1/,在其中緩存了任務的輸出。

再次執行

./gradlew --build-cache compileJava --info

> Task :app:compileJava UP-TO-DATE

Build cache key for task ':app:compileJava' is 3804aa4dacefba7c96c077f8de82ae3d

Skipping task ':app:compileJava' as it is up-to-date.

BUILD SUCCESSFUL in 1s

1 actionable task: 1 up-to-date

因為我們沒有做任何改動,build目錄里已經最新的輸出了,所以compileJava任務會跳過,此時任務被標記為UP-TO-DATE。

執行./gradlew clean刪除app的build目錄,然后再執行

./gradlew --build-cache compileJava --info?

> Task :app:compileJava FROM-CACHE

Build cache key for task ':app:compileJava' is db35214e1886f8b0ebbcc16e2fa7a618

Task ':app:compileJava' is not up-to-date because:

? Output property 'destinationDirectory' file /Users/xx/Downloads/gradle-project/app/build/classes/java/main has been removed.

? Output property 'destinationDirectory' file /Users/xx/Downloads/gradle-project/app/build/classes/java/main/gradle has been removed.

? Output property 'destinationDirectory' file /Users/xx/Downloads/gradle-project/app/build/classes/java/main/gradle/project has been removed.

? Output property 'options.generatedSourceOutputDirectory' file /Users/xx/Downloads/gradle-project/app/build/generated/sources/annotationProcessor/java/main has been removed.

Loaded cache entry for task ':app:compileJava' with cache key db35214e1886f8b0ebbcc16e2fa7a618

BUILD SUCCESSFUL in 1s

1 actionable task: 1 from cache

任務標記為FROM-CACHE,并且從緩存中加載了上次執行的輸出,日志中也有提示:

Loaded cache entry for task ':app:compileJava' with cache key db35214e1886f8b0ebbcc16e2fa7a618

?另外,app的build目錄也有了,里面的輸出應該就是直接從build cache中拿過來的。

?再再一次執行./gradlew --build-cache compileJava --info, 任務又是UP-TO-DATE了。

> Task :app:compileJava UP-TO-DATE

所以,對于要執行的任務,只要項目里已經存在最新輸出,它就是UP-TO-DATE;否則如果任務啟用構建緩存,并且在緩存里有最新輸出,就是FROM-CACHE。?

可緩存任務和不可緩存任務

在Gradle中并非所有任務都可以或應該被緩存,除了少數內置任務是可緩存外,大部分任務由于各種原因(如不可預測的輸出、外部依賴、任務配置等)可能不適合緩存。這些任務通常被標記為non-cacheable。

使用--build-cache選項可以讓Gradle啟用構建緩存功能。當這個選項被啟用時,Gradle會嘗試緩存可緩存任務的輸出,并在后續構建中重用這些輸出。

對于non-cacheable任務,Gradle會忽略構建緩存機制,并總是執行這些任務。通常是因為這些任務的輸出可能依賴于不可預測或不可重復的因素,或者任務本身的配置不允許緩存。

開發者也可以顯式地配置這類任務使其可緩存。

要確定一個任務是否可緩存,你可以查看任務的輸出。如果任務有一個buildCacheable屬性,并且它被設置為true,那么該任務就是可緩存的。如果任務沒有明確的buildCacheable屬性設置,或者它被設置為false,那么該任務就是non-cacheable的。

構建緩存的有效性還取決于構建環境的穩定性和一致性。如果構建環境經常變化(例如,使用了不同的構建機器或文件系統),那么構建緩存的效果可能會受到限制。因此,在使用構建緩存時,確保構建環境的一致性是非常重要的。

開發任務

在開發Gradle任務時,我們有兩個選擇:

1.使用現有的Gradle任務類型,比如Zip,Copy或Delete

2.創建自己的任務類型,比如MyResolveTask或者CustomTaskUsingToolchains

任務類型就是是Gradle Task類的子類。

對于Gradle任務,有三種狀態需要考慮:

1.注冊任務 - 在構建邏輯中使用一個任務(由您實現或由Gradle提供)。

2.配置任務 - 定義任務的輸入和輸出。

3.實現任務 - 創建一個自定義任務類(即自定義類型)

注冊通常使用register()方法完成。

配置任務通常使用named()方法完成。

實現任務通常是通過擴展Gradle的DefaultTask類來完成的:

①: 注冊Copy類型的myCopy任務。

②: 根據Copy API為注冊的myCopy任務配置它所需的輸入和輸出。

③: 實現一個名為MyCopyTask的自定義任務類型,它擴展了DefaultTask并定義了copyFiles任務操作。

1.注冊任務

我們可以通過在構建腳本和插件中注冊任務來定義Gradle要執行的操作。

使用字符串作為任務名來定義任務:

//build.gradle.kts

tasks.register("myCopy") {

?? doFirst {

? ? ? ? // Task action = Execution code

? ? ? ? // Run before exiting actions

? ? }

? ? doLast {

? ? ? ? // Task action = Execution code

? ? ? ? // Run after existing actions

? ? }

}

register()方法會將myCopy任務添加到TaskCollection中。

2.配置任務

Gradle任務必須經過配置來完成他們的操作。比如一個任務需要ZIP一個文件,我們就必須要配置文件名和文件位置。這可以參考Gradle Zip任務提供的API,學習如何正確進行配置。

在上圖示例中,我們注冊了一個myCopy任務

tasks.register<Copy>("myCopy")

我們可以在注冊的時候就立即用代碼塊配置任務:

tasks.register<Copy>("myCopy") {

?? from("resources")

?? into("target")

?? include("**/*.txt", "**/*.xml", "**/*.properties")

}

因為這個任務是Copy類型, 是Gradle支持的任務類型,所以可以使用Copy API,如from、to。

之后在需要的地方,都可以通過named()方法查找對應名字的任務來配置:

//build.gradle.kts

tasks.named<Copy>("myCopy") {

? ? from("resources")

? ? into("target")

? ? include("**/*.txt", "**/*.xml", "**/*.properties")

}

?注意,在named()調用時,如果指定的任務還沒有注冊,就會構建失敗。

3.實現任務

Gradle提供了很多任務類型,包括 Delete, Javadoc, Copy, Exec, Tar和Pmd等等,如果都滿足不了我們的構建邏輯需求,我們可以實現一個自定義的任務類型。

要創建一個任務類型,需要擴展DefaultTask,然后定義為一個抽象類(不用是具體實現類):

//app/build.gradle.kts
abstract class MyCopyTask extends DefaultTask {}

Gradle 會通過解析?build.gradle?文件中的配置動態創建任務實例,這些實例是任務類的具體實現,它們包含了在配置中設置的所有參數和指定的動作。

task("taskName")與tasks.register("taskName")

在 Gradle 中,task("taskName")?和?tasks.register("taskName")?都被用來創建新的任務,但它們屬于不同的 API 并具有一些細微的差別和用法上的考慮。

傳統 DSL(領域特定語言)方式:

task("taskName")?是 Gradle 的傳統 DSL(領域特定語言)方法,用于在?build.gradle?文件中聲明一個任務。這種方式相對直觀和簡單,適用于簡單的任務定義。

任務注冊(Tasks API)方式:

tasks.register("taskName")?是 Gradle Tasks API 的一部分,用于以編程方式注冊任務。它提供了更多的靈活性和控制,尤其是在需要基于其他任務或項目配置動態創建任務時。

主要區別:傳統 DSL 方法在配置階段就執行了任務的配置代碼,而 Tasks API 則允許延遲配置,直到執行階段才執行配置代碼。這有助于避免在配置階段發生不必要的副作用。

隨著 Gradle 的不斷進化,Tasks API 被認為是更現代和推薦的方式來創建和注冊任務。

tasks.register("taskName")?實現延遲配置的原理主要基于 Gradle 的任務生命周期和任務注冊機制。

在 Gradle 構建的生命周期中,任務(Task)的創建和配置是分開的。傳統的?task("taskName")?語法在項目的配置階段(configuration phase)就立即創建并配置了任務。這意味著,即使在任務從未被執行的情況下,其配置代碼也會被執行。這有時可能會導致不必要的副作用,比如提前計算了某些值,或者執行了只在任務執行時才需要的邏輯。

相比之下,tasks.register("taskName")?使用了一種不同的方法。這個方法實際上并沒有立即創建任務,而是注冊了一個任務工廠(TaskFactory)。這個工廠會在任務首次執行時(execution phase)被調用,從而創建任務實例并執行其配置,這就是所謂的“延遲配置”(lazy configuration)。

具體來說,當你調用?tasks.register("taskName")?時,Gradle 會創建一個?TaskRegistration?對象,該對象封裝了任務的配置邏輯(即你傳遞給?register?方法的閉包)。這個?TaskRegistration?對象會被添加到 Gradle 的任務容器中,但不會立即創建任務實例。

當 Gradle 執行階段到來,并且需要執行名為 "taskName" 的任務時,Gradle 會從任務容器中檢索相應的?TaskRegistration?對象,并調用其工廠方法來創建任務實例。此時,閉包中的配置邏輯才會被執行,從而配置新創建的任務實例。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/10864.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/10864.shtml
英文地址,請注明出處:http://en.pswp.cn/web/10864.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

4.5網安學習第四階段第五周回顧(個人學習記錄使用)

本周重點 ①部署域環境&#xff08;Win2008&#xff09; ②域組策略 ③域內信息收集 ④(重點)哈希傳遞攻擊PTH ⑤MS14-068 提權漏洞 ⑥黃金票據偽造 ⑦白銀票據偽造 ⑧ZeroLogon (CVE-2020-1472) 漏洞復現 本周主要內容 ①部署域環境&#xff08;Win2008&#xff09;…

【算法】滑動窗口——串聯所有單詞的子串

今天來以“滑動窗口”的思想來詳解一道比較困難的題目——串聯所有單詞的子串&#xff0c;有需要借鑒即可。 目錄 1.題目2.下面是示例代碼3.總結 1.題目 題目鏈接&#xff1a;LINK 這道題如果把每個字符串看成一個字母&#xff0c;就是另外一道中等難度的題目&#xff0c;即&…

對象,字符串的解構賦值

大家想了解更多&#xff0c;可以去看阮一峰的ECMAScript6(ES6)標準入門課程 對象 簡介 解構不僅可以用于數組&#xff0c;還可以用于對象。 let { foo, bar } { foo: aaa, bar: bbb }; foo // "aaa" bar // "bbb" 對象的解構與數組有一個重要的不同。…

[CAM_REQ_MGR_EVENT_MAX]高通6225平臺相機老化異常重啟

報錯log 相機老化出現20/7萬比例的老化異常重啟&#xff0c;具體報錯log入下 <4>[ 167.506585] [1970:01:02 18:52:26](0) [0:swapper/0]cam_v4l2_event_queue_notify_error: 251 callbacks suppressed 7 3339<6>[ 167.506602] [1970:01:02 18:52:26](0) [0:swap…

面試試題一

封裝&#xff08;Encapsulation&#xff09; 面試問題&#xff1a; 封裝在面向對象編程中扮演什么角色&#xff1f;如何在Java中實現封裝&#xff1f;有哪些最佳實踐可以幫助提高類的封裝性&#xff1f; 詳細答案&#xff1a; 封裝的角色&#xff1a; 封裝是面向對象編程的核…

CMake 的繼承關系

1. CMake如何確定繼承關系 在 CMake 中&#xff0c;父子關系是通過文件系統中的目錄結構來定義的。當你在一個目錄中創建一個 CMakeLists.txt 文件時&#xff0c;該目錄就被視為一個 CMake 項目的目錄&#xff0c;而該文件中的內容將被用于配置和構建該目錄中的項目。 當你在父…

不同路徑| 和 不同路徑||

不同路徑| 一個機器人位于一個 m x n 網格的左上角 &#xff08;起始點在下圖中標記為 “Start” &#xff09;。 機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角&#xff08;在下圖中標記為 “Finish” &#xff09;。 問總共有多少條不同的路徑&#xf…

Tomcat啟動閃退問題解決辦法

本文將通過一系列診斷步驟幫助您找出原因&#xff0c;并提供相應的解決辦法。 診斷步驟 查看日志文件 Tomcat的日志文件是解決啟動問題的第一線工具。查看logs目錄下的catalina.out和其他日志文件&#xff0c;這些文件經常記錄了錯誤信息和系統崩潰的線索。 cat /path/to/to…

C++編程與朱元墇的關系

學編程和英語沒關系&#xff0c;我說這句話&#xff0c;沒人會相信&#xff0c;也不會有人說我什么嘩眾取寵。 我說學編程和朱元墇有關系&#xff0c;一定有人說我放P&#xff0c;其實這個P也和朱元墇有關系&#xff0c; 和朱元墇有什么P關系啊。 真有這P事啊&#xff0c; 朱元…

LeetCode刷題筆記之圖論

1. 797【所有可能的路徑】 題目&#xff1a; 給你一個有 n 個節點的 有向無環圖&#xff08;DAG&#xff09;&#xff0c;請你找出所有從節點 0 到節點 n-1 的路徑并輸出&#xff08;不要求按特定順序&#xff09;。graph[i] 是一個從節點 i 可以訪問的所有節點的列表&#xf…

大學生體質測試|基于Springboot+vue的大學生體質測試管理系統設計與實現(源碼+數據庫+文檔)

大學生體質測試管理系統 目錄 基于Springboot&#xff0b;vue的大學生體質測試管理系統設計與實現 一、前言 二、系統設計 三、系統功能設計 1系統功能模塊 2管理員功能模塊 3用戶功能模塊 4教師功能模塊 四、數據庫設計 五、核心代碼 六、論文參考 七、最新計算…

MySQL數據庫基礎功能

MySQL是一種常用的關系型數據庫管理系統&#xff0c;它廣泛應用于網站開發、數據分析和其他許多領域。 咋可以不專業搞這個&#xff0c;但是基礎的最好能看懂和應用&#xff0c;快去學習吧 下面是10個不同案例&#xff0c;展示MySQL的用法。 ①創建數據庫&#xff1a;使用CR…

C++筆試強訓day20

目錄 1.經此一役小紅所向無敵 2.連續子數組最大和 3.非對稱之美 1.經此一役小紅所向無敵 鏈接 簡單模擬即可。 需要注意的是&#xff1a; 除完之后有無余數&#xff0c;若有&#xff0c;則還可以再挨一次打。 #include <iostream> using namespace std; #define in…

設計模式——結構型模式——代理模式(靜態代理、動態代理:JDK、CGLIB)

目錄 代理模式 代理模式簡介 代理模式的分類 代理模式組成 代理模式的優缺點 靜態代理 背景前置 編寫代碼 JDK動態代理 編寫代碼 使用Arthas分析JDK動態代理底層原理 CGLIB動態代理 編寫代碼 三種代理的對比 代理模式使用場景 代理模式 代理模式簡介 代理模式屬…

Mybatis操作數據庫的兩種方式:Mapper代理模式

1.Mapper代理模式的特點 程序員沒有寫接口的子實現——直接獲取數據庫的數據 因為Mybatis定義了一套規則&#xff0c;對方法進行了實現&#xff0c;程序員只要遵循這套方法就可以直接使用 2.如何實現Mapper代理模式 步驟&#xff1a; 1.創建一個dao接口&#xff0c;在接口…

java項目之英語知識應用網站源碼(springboot+vue+mysql)

風定落花生&#xff0c;歌聲逐流水&#xff0c;大家好我是風歌&#xff0c;混跡在java圈的辛苦碼農。今天要和大家聊的是一款基于springboot的英語知識應用網站。項目源碼以及部署相關請聯系風歌&#xff0c;文末附上聯系信息 。 項目簡介&#xff1a; 英語知識應用網站的主要…

【免費】AME最新Adobe Media Encoder電腦軟件安裝包2024-2018支持WIN和MAC

Adobe MediaEncoder「Me」2024是一款功能強大的轉碼和媒體處理軟件&#xff0c;它不僅能輕松應對各種媒體文件的編碼和導出需求&#xff0c;還支持多種視頻格式和分辨率&#xff0c;讓你的視頻處理變得更加高效。此外&#xff0c;該軟件界面簡潔明了&#xff0c;操作簡便&#…

【一步一步了解Java系列】:了解Java與C語言的運算符的“大同小異”

看到這句話的時候證明&#xff1a;此刻你我都在努力~ 加油陌生人~ 個人主頁&#xff1a; Gu Gu Study ?? 專欄&#xff1a;一步一步了解Java 喜歡的一句話&#xff1a; 常常會回顧努力的自己&#xff0c;所以要為自己的努…

【Element-UI快速入門】

文章目錄 **Element-UI快速入門****一、Element-UI簡介****二、安裝Element-UI****三、引入Element-UI****四、使用Element-UI組件****五、自定義Element-UI組件樣式****六、Element-UI布局組件****七、Element-UI表單組件****八、插槽&#xff08;Slots&#xff09;和主題定制…

【數據結構】排序(一)—— 希爾排序(思路演進版)

目錄 一、常見的排序算法分類 二、常見排序算法的實現 2.1插入排序 2.1.1基本思想 2.1.2直接插入排序 思路 step1.單趟控制 step2.總體控制 代碼實現 測試 特性總結 2.1.3 希爾排序( 縮小增量排序 ) 基本思想 思路演進 &#x1f308;1.代碼實現單組排序&#…