Gradle相依性配置筆記

在Gradle裡的Java plugin相依管理中,有幾個常見的相依性配置(dependency configurations),像compile、runtime、compileOnly、testCompile、testRuntime、testCompileOnly…等。這裡大致上描述介紹一下:

compile – 專案在編譯的階段就需要這些相依函式庫內容,這包含相依庫的子依賴,這些內容最後都會加入到classpath裡去了。 例如Spring、Hibernate的相依庫。

runtime – 繼承於compile。專案在執行的時候會需要這些相依庫。例如MySQL driver的相依庫。備註:假設專案使用一個相依A,而A又相依B,專案編譯階段只需要A,但執行階段時其實是需要A和B,這也是為何配置compile的相依可以被runtime看見,但反過來卻不一定正確。

compileOnly -繼承於compile。這些相依庫基本上只有專案編譯的階段被使用,專案執行階段的時候不被使用,這些內容最後不會被加入到runtime的classpath裡。像source-only annotations。備註:某相依庫的API在編譯時段被需要,但實作的內容則是由執行時的應用程式、其他相依、環境所提供。

用更直覺的方式舉例,如果今天在IDE裡寫程式,需要在某A相依庫裏使用Person.java,且這個類別會用在專案主要執行邏輯中,那麼一開始IDE會先跳紅字,因為此時尚未引入A相依庫。如果此時是用compile配置,紅字會消失,執行會正常。如果用compileOnly配置,紅字會消失,但執行會失敗。如果用runtime配置,紅字依然在,無法執行。這時候compile是最佳的選擇。

假設情境改為需要引用Connector.java,它並未出現在我們的程式裡,但在執行的時候會使用到這隻類別,那麼此時使用配置,則基本上IDE根本不會出現紅字,執行會成功。如果用runtime配置,也會執行成功。用compileOnly配置則會失敗,因為該配置的相依庫並不會出現在runtime classpath裏,執行時自然找不到該類別。runtime在這個例子最適合。

最後一個情境,在IDE上使用了Shape.java的一個介面,但基本上Shape的實作內容並不是由我們實作,而是會根據環境的jar檔或是其他相依執行階段時提供,那麼此時用compile配置,則紅字會消失,執行期間可能會因找不到實作失敗。用runtime配置,紅字依然在,無法執行。compileOnly配置,紅字會消失,執行期間可能會因找不到實作失敗。compile跟compileOnly的結果是相同,但因為要區分該相依的結果是編譯會成功,但執行還是可能找不到實作相依而失敗這類型的相依庫,這邊選擇用compileOnly最洽當。

當使用java plugin時,基本上會看到src/main/java和src/test/java兩個source來源。上面三個相依配置主要是應用在main這層底下,而有前綴test如testCompile、testRuntime、testCompileOnly這些配置其實是大同小異,但他們則是多套用test的階層底下的內容。這樣的配置是正常且合理的,因為主程式跟測試程式本也不該放在一塊。一個常見只會在test測試時才會使用的相依庫,例如JUnit的相依庫。

另一個常搞混的是war plugin裡面新增的兩個配置providedCompile、providedRuntime。當有前綴provided-的這兩個意思主要是指最後在classes裡面的內容是不會被包到war檔裡面。這很重要,因為某些相依庫是為了開發階段方便而存在,在部署的時後可能因環境不同而不被需要。例如embeded tomcat、dev tools等類似相依庫。

最後還有另一個java-library plugin,裡面多了更多配置如api、implementation、runtimeOnly,因為自己不常用,也不依依介紹,有興趣的可以參考這裡

以上整理這些常用配置,也釐清哪些相依配置是歸屬於哪個plugin裏,也搞懂什麼情況該用什麼配置比較適合,不再只是單用compile無敵的觀念。好的習慣會幫助在環境上的設置、相依性的debug、或是部署時的資安有所幫助,也可以省去包了一堆不必要的錯,或是解了一堆根本不需要顧慮的紅字,其實好處是多多的。

參考:

  • https://docs.gradle.org/current/userguide/artifact_dependencies_tutorial.html
  • https://docs.gradle.org/3.3/userguide/java_plugin.html#sec:java_plugin_and_dependency_management
  • https://blog.gradle.org/introducing-compile-only-dependencies
  • https://stackoverflow.com/questions/16700939/difference-between-compile-and-runtime-configurations-in-gradle
  • https://www.gesellix.net/post/providedcompile-and-compile-dependencies-with-gradle/
  • https://docs.gradle.org/current/userguide/java_library_plugin.html

Leave a Reply

當第一個留言者!

avatar
wpDiscuz