【認識 Gradle】(7)Java 專案相依管理
- gradle-series
編:此文撰寫於 2014 年初,當時的 SoneTypa Nexus 已經改名為 Nexus Repoistory 並分為 OSS 版本與 Pro 版本
在 Maven 帶給開發者許多好的體驗,相依性管理是其中對一般開發者較具有吸引力的因素。Gradle 納入套件管理的功能,並且能使用 Maven Repository 作為套件下載來源。在 Gradle 管理套相的相依性,可以寫成這樣:
apply plugin: 'java'
/* 設定 maven repository server $ */
repositories {
mavenCentral()
}
/* 宣告專案的相依函式庫 $ */
dependencies {
compile group: 'commons-logging', name: 'commons-logging', version: '1.1.1'
compile group: 'log4j', name: 'log4j', version: '1.2.16'
}
使用 repositories
設定決定套件的來源,再使用 dependencies
宣告相依關係。這樣寫幾乎就是快速上手課程裡會學到的內容,不過文章才剛開始,我們不會那麼早結束這個『話題』。
記得看過一則討論是使用 Maven 管理相依性問題是否實用嗎?讓專案直接與使用到的函式庫(JARs)包含開發環境的相依套件設定,通通送進版本控制系統。當有人需要重新建起開發環境時,只要由版本控制系統取回匯入 IDE 後就能使用。我必需承認這樣確實很方便,不過有幾個問題需要思考。
首先,版本控制系統較擅長處理純文字的檔案,對於函式庫這類非純文字檔的存儲效率不太好,無法以較省空間的方式儲存。隨著函式庫更換版本的次數越多,版本控制系統檔案庫虛胖得越快。若你的團隊可能有多個地理位置,只有靠近版本控制系統的人可以使用愉快。專案開發使用的函式庫檔案越大,由版本控制系統取出的時間越久。這雖然是理所當然的事,但曾待過這樣的團隊,版本控制系統的伺服務在遠方,只有與它同辦公室的同事覺得取出專案很快。若你們團隊都離版本控制系統伺服務很近,那麼這個『等待』的問題應該還算在能接受的範圍。
另一個問題是,在同一組開發團隊裡,使用的解決方案可能會很相近,使用的函式庫相互重複的情況相當明顯。相同的 Logging Tool、相同的 IoC Framework、相同的 Web Framework、相同的 ORM Framework 或公司累積的內部函式庫。可以試著算算公司內有多少相近的專案,並想一下 N 個專案,就有 N 組重複的函式庫在版本控制系統內,最好提醒管理版本控制系統伺服器端的同事,硬碟空間不能太小氣。若換成是使用『套件相依管理』的功能,那麼它的變動只是一個文字檔內的幾行字,對於版本控制系統的負擔很小。
除了上述的缺點之外,我們得回到相依管理的本質。它並不是在管理一個一個的 JAR 檔案是否要存在這個專案。它是在管理『一組』JARs 檔,它們一起出現是具有意義的,而那個意義才是『相依性』管理的核心。就像在專案中使用 Hibernate 或 Spring Framework 不會只有它們本身提供的 JARs 就足夠,還有相依的第三方函式庫。若單純以獨立的 JAR 檔的角度來管理專案需要用到的函式庫,那隨著專案的發展有些功能已不再使用,年代久遠之後,也沒有人會記得哪一個 JAR 檔是為了什麼目的而加進來的,特別是這個 JAR 檔為了滿足函式庫自身相依性的情況。
相依關係
我們使用 gradle tasks
查詢可用的 task,當你加入 dependencies
設定後,會多出相關的 task:
Help tasks
----------
dependencies - Displays all dependencies declared in root project 'gradleLab'.
dependencyInsight - Displays the insight into a specific dependency in root project 'gradleLab'.
help - Displays a help message
projects - Displays the sub-projects of root project 'gradleLab'.
properties - Displays the properties of root project 'gradleLab'.
tasks - Displays the tasks runnable from root project 'gradleLab'.
使用 dependencies
task 可以查詢專案目前的相依關係,其中 compile
設定 (專用術語是 dependency configurations) ,就是在 build.gralde
內寫的設定,其他部分是設定 compile
相依套件時自動設定的:
qty:gradleLab qrtt1$ gradle dep
:dependencies
------------------------------------------------------------
Root project
------------------------------------------------------------
archives - Configuration for archive artifacts.
No dependencies
compile - Compile classpath for source set 'main'.
+--- commons-logging:commons-logging:1.1.1
\--- log4j:log4j:1.2.16
default - Configuration for default artifacts.
+--- commons-logging:commons-logging:1.1.1
\--- log4j:log4j:1.2.16
runtime - Runtime classpath for source set 'main'.
+--- commons-logging:commons-logging:1.1.1
\--- log4j:log4j:1.2.16
testCompile - Compile classpath for source set 'test'.
+--- commons-logging:commons-logging:1.1.1
\--- log4j:log4j:1.2.16
testRuntime - Runtime classpath for source set 'test'.
+--- commons-logging:commons-logging:1.1.1
\--- log4j:log4j:1.2.16
BUILD SUCCESSFUL
目前專案看單純僅有二個相依套件設定,我們試引用其它稍為巨大一點的函式庫試試,在 dependencies 設定內只留下 AWS SDK for Java:
com.amazonaws:aws-java-sdk:1.+
compile - Compile classpath for source set 'main'.
\--- com.amazonaws:aws-java-sdk:1.+ -> 1.6.11
+--- commons-logging:commons-logging:1.1.1
+--- org.apache.httpcomponents:httpclient:4.2
| +--- org.apache.httpcomponents:httpcore:4.2
| +--- commons-logging:commons-logging:1.1.1
| \--- commons-codec:commons-codec:1.6
+--- commons-codec:commons-codec:1.3 -> 1.6
+--- com.fasterxml.jackson.core:jackson-core:2.1.1
+--- com.fasterxml.jackson.core:jackson-databind:2.1.1
| +--- com.fasterxml.jackson.core:jackson-annotations:2.1.1
| \--- com.fasterxml.jackson.core:jackson-core:2.1.1
+--- com.fasterxml.jackson.core:jackson-annotations:2.1.1
\--- joda-time:joda-time:[2.2,) -> 2.3
由相依關係可以看出,aws-java-sdk
宣告時指定需要版號 1.
開頭的,它在 1.
相關的版本找目前最新的 1.6.11
,它本身的相依於:
- commons-logging:commons-logging:1.1.1
- org.apache.httpcomponents:httpclient:4.2
- commons-codec:commons-codec:1.3
- com.fasterxml.jackson.core:jackson-core:2.1.1
- com.fasterxml.jackson.core:jackson-databind:2.1.1
- com.fasterxml.jackson.core:jackson-annotations:2.1.1
- joda-time:joda-time:[2.2,)
在 org.apache.httpcomponents:httpclient:4.2 套件它又有自己相依的套件:
- org.apache.httpcomponents:httpcore:4.2
- commons-logging:commons-logging:1.1.1
- commons-codec:commons-codec:1.6
我們能觀察到 commons-codec:commons-codec:1.6
與 aws-java-sdk 指定的 1.3 版不同,相依性管理的機制會選用較新的那一組,這也是為什麼它最後被標示為:
commons-codec:commons-codec:1.3 -> 1.6
因為原先指定的版本是 1.3,但其它相依套件指定了更新的版本,於是最終使用 1.6 版。
另一組是只留下 Windows Azure SDK for Java:
compile 'com.microsoft.windowsazure:microsoft-windowsazure-api:0.+'
compile - Compile classpath for source set 'main'.
\--- com.microsoft.windowsazure:microsoft-windowsazure-api:0.+ -> 0.4.6
+--- com.sun.jersey:jersey-client:1.13
+--- javax.inject:javax.inject:1
+--- com.sun.jersey:jersey-json:1.13
| +--- org.codehaus.jettison:jettison:1.1
| | \--- stax:stax-api:1.0.1
| +--- com.sun.xml.bind:jaxb-impl:2.2.3-1
| | \--- javax.xml.bind:jaxb-api:2.2.2
| | +--- javax.xml.stream:stax-api:1.0-2
| | \--- javax.activation:activation:1.1
| +--- org.codehaus.jackson:jackson-core-asl:1.9.2
| +--- org.codehaus.jackson:jackson-mapper-asl:1.9.2
| | \--- org.codehaus.jackson:jackson-core-asl:1.9.2
| +--- org.codehaus.jackson:jackson-jaxrs:1.9.2
| | +--- org.codehaus.jackson:jackson-core-asl:1.9.2
| | \--- org.codehaus.jackson:jackson-mapper-asl:1.9.2 (*)
| \--- org.codehaus.jackson:jackson-xc:1.9.2
| +--- org.codehaus.jackson:jackson-core-asl:1.9.2
| \--- org.codehaus.jackson:jackson-mapper-asl:1.9.2 (*)
+--- commons-logging:commons-logging:1.1.1
+--- javax.mail:mail:1.4.5
| \--- javax.activation:activation:1.1
\--- org.apache.commons:commons-lang3:3.1
Windows Azure 相依關係就更多層,樹狀結構更深。在專案使用越多的第三方套件,那麼要明確瞭了哪一個 JAR 檔的來歷與功用,為何將它加入專案內就越加困難。並且使用相依性管理功能能指定一個可接受的版本號範圍,對 Windows Azure 指定的是 0.+,就是要使用主版號為 0 的套件中最新的版本,這功能能輔助專案的相依套件隨時更新到足夠新的狀態。
更新到足夠新的狀態有正反兩種意義:
- bugfix 與 patch 修補的版本會更得上最近的發佈版本
- 潛在的 bug 也隨著最新的版本引入
在希望專案自動緊追著最新發佈版本的情況採用自動版本號,不希望它自動更新的情況下使用固定的版本號。以 AWS SDK for Java 為例,在公司的專案最初設定自動版號,但發現一旦 AWS 有新服務發表,或是一些我們不會用到的功能修好 bug 就會有新的版本。由於它變動得太過頻繁,重新下載相依檔案就會花一點時間,但我們又用不到它更新的部分,於是將它設為固定版號的。
公司內部發佈的套件相依設定皆為自動版號,因為不會無來由地發佈新版,肯定是修了 Bug 或要加新功能讓需要的專案使用。它仍然有改成固定版號的時機,例如:新版的需要測試後才能發佈,那麼現行的產品就應相依於特定版號,直到新版的確定要發佈且不會再有重大修改。另一個原因是規格變更前後版不相容,不過這情況就不建議改相依性的版號,而是新的版本要提昇主版號,表示為不相容。
相依關係設定
理解相依管理的優點後,在開發中如何使用它呢?對於沒有 Maven 或 Ant Ivy 使用經驗的讀者應該會有第一個疑惑, 在 dependencies 設定:
compile group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.+'
或寫成:
compile 'com.amazonaws:aws-java-sdk:1.+'
這套件資訊是怎麼來的呢?有幾個途經:
- 至該套件的官方網站查詢,通常手冊開發者的訊息會包含。
- 若是 open source 專案,由它的原始碼找答案它很可能是 Maven Project 或 Gradle Project。
- 使用套件查詢網站查詢,但仍建議比對官網目前發部的版本。
使用套件查詢網站時,keyword 通常是以專案名稱,或該專案使用的 package name 為主,例如查詢 aws:
找到目標後進去它的內頁:
選擇需要的版本後,依專案工具選擇適當的設定值。請點選 Gradle 頁籤:
在 Gradle 頁籤內的資訊能直接填寫至 dependencies 內,或將它改成動態版本的宣告。
套件伺服器
當專案開始利用 Gradle 管理套件的便利設施後,隨著管理與使用的需求,架設套件伺服器是隨之而來的必要工作。原先我們針對套件伺服器的設定只有簡單地採用 Maven 公開伺服器,單純作為 Open Source 函式庫的使用者來說,它是方便的:
repositories {
mavenCentral()
}
不過對於要開發私有程式的商業單位,多數的情況不會將自己公司的函式庫發佈至 Maven 公開伺服器。取而代之的是架設自有的套件伺服器,將公司內部的函式庫發佈在私有的伺服器上,後續專案只要設定好 repositories 就能使用,例如:
repositories {
maven {
credentials {
username 'username-for-your-server'
password 'password-for-your-server'
}
url "http://url-to-your-repo-server"
}
}
有了私有伺服器,通常就不會額外宣告 mavenCentral()
,因為它同時作為『代理伺服器』替開發者向 Maven 公開伺服器下載需要的檔案,這樣亦可減少非必要的網路傳輸。
我們能在網路上找到許多套件伺服器,以本系列常引用的 Nexus 來說,它就是其中一套。它提供 Open Source 版與商業版,如果沒有特殊的需求用 Open Source 版已經堪用。它是以 Java Solution 寫成的,安裝的方法可參閱其官方文件 Installing Nexus。它有二種安裝方式:一種是安裝 WAR 檔版本,就使用你原有的 Java Web Container 即可,或是用獨立執行的版本(它是使用 jetty)。
qty:nexus-2.7.1-01-bundle qrtt1$ ls -alh
total 0
drwx------@ 4 qrtt1 staff 136B 1 18 12:37 .
drwx------+ 32 qrtt1 staff 1.1K 1 18 12:30 ..
drwxr-xr-x@ 10 qrtt1 staff 340B 1 10 11:05 nexus-2.7.1-01
drwxr-xr-x@ 5 qrtt1 staff 170B 1 18 12:30 sonatype-work
以獨立執行的版本為例,下載完解壓縮後會有二個目錄。nexus 開頭的目錄為程式的目錄,而 sonatype-work 是預設存放下載資料的目錄(可以透過設定變更,維護的工作主要也是備份這個目錄的資料)。對大多數管理者來說有額外設定的需求,例如:改管理者帳號、改 port 號。
針對 Web Container 部分的設定,可由程式目錄下的 conf/nexus.properties
修改:
qty:nexus-2.7.1-01-bundle qrtt1$ cat nexus-2.7.1-01/conf/nexus.properties
# Sonatype Nexus
# ==============
# This is the most basic configuration of Nexus.
# Jetty section
application-port=8081
application-host=0.0.0.0
nexus-webapp=${bundleBasedir}/nexus
nexus-webapp-context-path=/nexus
# Nexus section
nexus-work=${bundleBasedir}/../sonatype-work/nexus
runtime=${bundleBasedir}/nexus/WEB-INF
其他部分需啟動程式後,由 Web Console 修改。像是他預設的管理者帳號:admin/admin123,就是需要修改的。這部分就不在本文的重點,依讀者依使用手冊 Post-Install Checklist 的建議修改。額外需要提醒讀者的是:
- 將 anonymous 使用者停用(或刪除),預設是任何人可以在不登入 nexus 的情況下讀取 library。
- 變更 admin 使用者密碼,或停用另建管理者帳號。
- 替不同單位建立不同的 deploy 帳號。
登入 nexus 後,在 repositories 管理頁可以看到許多事先建立完成的 repository:
可以觀察到每一個 repository 都有一個 type:
- proxy:那些常用的、公開的 Maven Repository 已預先建立成 proxy 的 type,當你以這台自建的 nexus server 作為 repository 時,它就會作為代理人替你去向公開 repository 抓取相依套件,存放在 sonatype-work 目錄內。第二次再抓取出,若沒有更新的版本就直接回傳先前抓取的版本。
- hosted:type 為 hosted 代表是使用者自行發佈的內容,我們常用的就是 Releases 與 Snapshots 這二組 repository,也有人更細分出 3rd party,或是全都用 Releases 發佈。
- group:列在第 1 項的 Public Repositories 標為 group type 的是一種特殊的 repository,可以想像成是 Server Side 的反向代理,因為它本身沒有直接 hosted 或 proxy 的功能,而是將一些既有的 repository 聚合起來成為一個進入點。設定 Maven Repository 引用位置時可以設定這一組位置即可,不需要設定個別的 Releases 或 Snapshots Repository。
點開 group repository 的設定,可以看出它走訪不同 repository 的順序:
使用自有套件
完成自有 repository 架設後,將專案設定稍作修改即可將它發佈並在其他專案引用。在學習發佈之前,我們能先修改專案使用自己的 repository server,將原先的 mavenCentral()
換成自建的 repository:
注意!這是個簡單的示範,正式啟用前應建好新的帳號,而不是使用 admin 帳號,並確定好 server 固定 ip,而非 localhost 位置。
apply plugin: 'java'
apply plugin: 'maven'
repositories {
maven {
credentials {
username 'admin'
password 'admin123'
}
url "http://127.0.0.1:8081/nexus/content/groups/public/"
}
}
dependencies {
compile group: 'commons-logging', name: 'commons-logging', version: '1.1.1'
compile group: 'log4j', name: 'log4j', version: '1.2.16'
}
完成修改後,專案就不再直接抓取 Maven 公開的 repository,而是透過 nexus 作為 proxy 進行核對版本。若要對此專案進行發佈,需再加上 uploadArchives 設定,並指定要發佈的 repository 位置:
/* build.gradle */
apply plugin: 'java'
apply plugin: 'maven'
ext {
maven_group_id = 'codedata'
maven_artifact_id = 'gradle.happy.tour'
maven_version = '0.1.3'
}
dependencies {
compile group: 'commons-logging', name: 'commons-logging', version: '1.1.1'
compile group: 'log4j', name: 'log4j', version: '1.2.16'
}
apply from: 'mvn.gradle'
/* mvn.gradle */
apply plugin: 'maven'
ext {
maven_repo_id = 'admin'
maven_repo_pwd = 'admin123'
}
repositories {
maven {
credentials {
username maven_repo_id
password maven_repo_pwd
}
url "http://127.0.0.1:8081/nexus/content/groups/public/"
}
}
def enableUploadArchives = ext.has('maven_group_id') && ext.has('maven_artifact_id') && ext.has('maven_version')
if (enableUploadArchives) {
uploadArchives {
repositories {
mavenDeployer {
pom.groupId = maven_group_id
pom.artifactId = maven_artifact_id
pom.version = maven_version
def suffix = pom.version.contains("SNAPSHOT") ? "snapshots" : "releases"
repository(url: "http://127.0.0.1:8081/nexus/content/repositories/${suffix}/") {
authentication(userName: maven_repo_id, password: maven_repo_pwd)
}
}
}
}
}
讀者可以注意到,我們做了一些改變:
- 將 Maven 相關設定獨立到其它的檔案,在還沒有學會寫 plugin 前,單純透過 apply 來引用 script 是個方便的替代方案
- 在 uploadArchives 有個簡單的邏輯判斷。當版本號含 SNAPSHOT 字串時,就將 repository 設成 snapshot 的那一組,例如 0.1.2-SNAPSHOT。反之,則發佈至 releases 的那一組。
- uploadArchives 只在有滿足 mavengroupid、mavenartifactid、maven_version 才設定 repository 上傳。
一旦設定完成,我們能透過 gradle uploadArchives 指令上傳,並能看到顯示上傳到 Server 的訊息。下面範例是發佈 1.0 版本的訊息:
qty:HelloGradle qrtt1$ gradle uArc
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar UP-TO-DATE
:uploadArchives
Uploading: codedata/gradle.happy.tour/1.0/gradle.happy.tour-1.0.jar to repository remote at http://127.0.0.1:8081/nexus/content/repositories/releases/
Transferring 0K from remote
Uploaded 0K
BUILD SUCCESSFUL
Total time: 6.724 secs
接著,我們能在另一個專案引用它,我們使用動態版本號:
qty:UsingDeps qrtt1$ cat build.gradle
apply plugin: 'java'
apply plugin: 'maven'
dependencies {
compile group: 'codedata', name: 'gradle.happy.tour', version: '1.+'
}
apply from: 'mvn.gradle'
並能由 dependency task 查出目前的相依關係:
qty:UsingDeps qrtt1$ gradle dep
:dependencies
------------------------------------------------------------
Root project
------------------------------------------------------------
archives - Configuration for archive artifacts.
No dependencies
compile - Compile classpath for source set 'main'.
\--- codedata:gradle.happy.tour:1.+ -> 1.0
+--- commons-logging:commons-logging:1.1.1
\--- log4j:log4j:1.2.16
..................................................
接著讀者可做個簡單的練習:
- 在 HelloGradle 專案,發佈 1.1 版
- 觀察 UsingDeps 的相依關係是哪一版
結果是 UsingDeps 仍停留在 1.0 版,因為 gradle 並不會主動檢查 Server 端是否有新版本,可以下參數強制它檢查:
qty:UsingDeps qrtt1$ gradle dep --refresh-dependencies
:dependencies
------------------------------------------------------------
Root project
------------------------------------------------------------
archives - Configuration for archive artifacts.
No dependencies
compile - Compile classpath for source set 'main'.
\--- codedata:gradle.happy.tour:1.+ -> 1.1
+--- commons-logging:commons-logging:1.1.1
\--- log4j:log4j:1.2.16
..................................................
這樣透過 gradle 發佈與引用套件至自建 repository 相當方便我們管理自制的函式庫,需要注意的是相依的版本不會主動更新,需透過 --refresh-dependencies
強制它更新至最新版本。
使用 Maven 上傳函式庫
教完 Gradle 的上傳繼續談 Maven,這並不是讀者眼花,是因為有太多情況會遇到 Maven Project,特別是使用 Open Source 專案的情況,並非所有的專案都轉向 Gradle。所以,學習如何處理 Mavan 專案也是份重要的知識。儘管可以在網路上找到各種用 Gradle 上傳單一個 JAR 檔,或整組 Maven Project(或先轉成 Gradle Project)。做法上不太一致,那不如退回到對它支援對好的工具:用 Maven 上傳至 Maven Reposiotry。得利用 Maven 上傳,像是:
- 不管什麼原因,得上傳獨立的 JAR 檔。像是合作的伙伴沒有釋出原始碼,只給了編譯好的 JAR 檔,或是古早年代前人留下來的檔案。
- 修改其他 Open Source 的 Maven 專案:這通常是『等不及』或『等不到』發佈需要的函式庫時需要做的。等不及就是已經有 bug fixed 在版本控制系統內了,只是該專案 release 時間遙遙無期,至少它遠大於你本身的 deadline。而等不到的情況是,該專案沒有活動機象了,好家在還能 build 出 JAR 檔,只好拿著 source code 自己來吧。
用 Maven 上傳函式庫的方法就是使用 maven deploy plugin,不過我們不討論原本就是 Maven 專案並且已設好上傳位置的狀態。單純談使用 deploy plugin 內的 deploy-file 功能,用它來處理需要單檔上傳的情況。
設定 Maven Repository 證認資料
Maven 專案的 Repository 資訊是設定在專案內,但認證資料是設定在安裝目錄內的 $MAVEN_HOME/conf/settings.xml
,它的結構如下:
<settings>
<servers>
<server>
<id>my_maven_repo</id>
<username>admin</username>
<password>admin123</password>
</server>
</servers>
</settings>
使用 deploy plugin 時,需指定 server id my_maven_repo,它會找出對應的帳號與密碼。假設現在有個 legacy.jar 檔,我們要將它上傳至自建的 repository:
mvn deploy:deploy-file \
-Durl=http://127.0.0.1:8081/nexus/content/repositories/releases \
-DrepositoryId=my_maven_repo \
-Dfile=legacy.jar \
-Dpackaging=jar \
-DgroupId=example.com \
-DartifactId=foo.bar \
-Dversion=1.0
參數說明如下:
- 使用 deploy-file,在沒有事先撰寫 pom.xml 的情況下,能透過 url 參數指定 repository 位置。
- 參數 repositoryId 就是在 settings.xml 內設定的 server id,會用它來查出對應的認證資訊
- 參數 file 為欲上傳檔案的路徑
- packaging 為檔案格式,上傳 JAR 檔時填 jar 即可
- groupId、artifactId、version 都是 Maven 專案必填的項目
上傳過程顯示訊息如下:
qty:legacyJar qrtt1$ mvn deploy:deploy-file \
> -Durl=http://127.0.0.1:8081/nexus/content/repositories/releases \
> -DrepositoryId=my_maven_repo \
> -Dfile=legacy.jar \
> -Dpackaging=jar \
> -DgroupId=example.com \
> -DartifactId=foo.bar \
> -Dversion=1.0
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-deploy-plugin:2.5:deploy-file (default-cli) @ standalone-pom ---
Uploading: http://127.0.0.1:8081/nexus/content/repositories/releases/example/com/foo.bar/1.0/foo.bar-1.0.jar
Uploaded: http://127.0.0.1:8081/nexus/content/repositories/releases/example/com/foo.bar/1.0/foo.bar-1.0.jar (108 KB at 718.6 KB/sec)
Uploading: http://127.0.0.1:8081/nexus/content/repositories/releases/example/com/foo.bar/1.0/foo.bar-1.0.pom
Uploaded: http://127.0.0.1:8081/nexus/content/repositories/releases/example/com/foo.bar/1.0/foo.bar-1.0.pom (389 B at 7.6 KB/sec)
Downloading: http://127.0.0.1:8081/nexus/content/repositories/releases/example/com/foo.bar/maven-metadata.xml
Downloaded: http://127.0.0.1:8081/nexus/content/repositories/releases/example/com/foo.bar/maven-metadata.xml (294 B at 9.9 KB/sec)
Uploading: http://127.0.0.1:8081/nexus/content/repositories/releases/example/com/foo.bar/maven-metadata.xml
Uploaded: http://127.0.0.1:8081/nexus/content/repositories/releases/example/com/foo.bar/maven-metadata.xml (323 B at 6.2 KB/sec)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.971s
[INFO] Finished at: Sat Jan 25 22:20:05 CST 2014
[INFO] Final Memory: 3M/81M
[INFO] ------------------------------------------------------------------------
完工後即可在 gradle 專案內使用,例如:
dependencies {
compile group: 'codedata', name: 'gradle.happy.tour', version: '1.+'
compile group: 'example.com', name: 'foo.bar', version: '1.+'
}
另一種上傳形式是指定 pom.xml
,通常會用在本身是 Maven 專案有提供 pom.xml
,且我們需要將它上傳至自建 repository 的情況:
mvn deploy:deploy-file \
-Durl=http://127.0.0.1:8081/nexus/content/repositories/releases \
-DrepositoryId=my_maven_repo \
-Dfile=legacy.jar \
-DpomFile=your-pom.xml
能由 pom.xml 內提供的資訊就不需要寫出來,另外好處是它不再只是單一檔案上傳,還能在 pom.xml
內描述它的相依關係。
內容回顧
這次談到 Java 專案的相依性管理,理解相依管理的要點與重要性。學習使用 Gradle 將專案發佈成函式庫,並以 Maven 工具補足額外的上傳需求:
- 設定 reposiotry 與 uploadArchives
- 以 –refresh-dependencies 參數強制更新
- 使用 nexus oss 架設自有的 Maven Repository
- 使用 Maven 上傳非 Gradle 專案的函式庫
我們講述了如何引用、發佈、更新函式庫,並了解特定情況的上傳方式。期待讀者能在相依管理的機制下,獲得更舒適的開發體驗。
編:上傳至 Maven Repository 的用法,在新版的 Gradle 有不同的寫法,請讀者參考 Maven Publish Plugin