2011年4月15日

使用Gradle快速建立Jetty網站開發測試環境

開發Java網站最讓人畏懼的就是癡肥的開發環境,回想過去每次砸重金升級記憶體,幾乎都是為了要讓電腦負荷JavaEE的開發。最可怕的莫過於幾年前用Eclipse+JBoss+SQL Server再外掛虛擬機器,光啟動開發環境就得花上數分鐘,一下子就耗掉數GB記憶體,而之後每次寫完一小段程式碼,要Deploy到Server上進行測試,等待時間更是曠日費時。特別是在本來就不怎麼夠力的筆電上,這些噩夢到了後來把Groovy和一些lightweight的開發框架玩上手才開始好轉。

最近打造的輕量化開發環境,編輯器以輕巧的jEdit取代Eclipse,因為Eclipse對Groovy並沒有良好的支援,反而jEdit在客製化之後更能完全符合專案需求;而JavaEE容器一直以來都是用Tomcat為主,其實Tomcat一直是個穩定好用、速度也不賴的Container,但是在使用Grails一段時間後,發現其實更好的作法是在專案裏面內嵌一個Container,這樣一個Java的網站專案,就可以不必依賴其他伺服器軟體,只要用SVN或GIT取出網站目錄,下個build指令就可以獨立運作,不管遷移到任何一台開發機器,都可以不必重新安裝、設定Container,節省了開發階段測試所需的時間,更可以方便透過持續整合(CI)系統進行自動化測試。

簡單說明一下這種差異,傳統在開發JavaEE網站專案時,不管是Production或Development、Test環境,都需要建構三個項目。
  1. Container(即Java的網頁伺服器,如Tomcat等)
  2. WebApp(網站專案的程式碼及資源檔案)
  3. Database(MySQL或SQL Server等)
以上三個項目各自有不同需要維護的設定檔,而且經常要將函式庫(.jar檔)等放到合適的位置。而這三個項目,只有WebApp才是適合用版本控制系統管理檔案的部份。
對於不同的開發者在不同的機器上做開發時,可以透過版本控制系統,取得WebApp最新的異動,因此WebApp的部份算是很容易就可以遷移到不同台電腦上。

但是對於一個開發架構不良的JavaEE專案,開發人員除了維護專案自己專屬的程式碼外,還需要維護網路下載來的函式庫(.jar檔案等),並且要正確配置其他兩項Container、Database,才能使WebApp能夠正確進行開發及測試。因此這部份參雜了不少人工作業,每次遷移或建立新的開發環境,很多事情必須重新來過,過程還可能會出錯。

最重要的是,這種無法完善進行自動化的開發過程,會造成導入持續整合的困難。因為持續整合系統,是必須做到定時從版本控制系統取得最新的WebApp,並且自動完成編譯、打包、部屬、測試、產生文件及彙整報告等工作。但是當我們的專案需要加入某些新的東西,而除了改變WebApp,也同時需要改變Container或Database時,就造成持續整合系統很難自動化處理這些事情,所以必須由人工在將持續整合系統的環境進行調整。

更完善的持續整合,將能夠自動依照不同配置設定,產生新的虛擬機器,並且在虛擬機器中自動建置測試環境,取得版本控制系統上的程式碼,再進行一連串編譯及測試等動作。這種時候,若WebApp所需要的測試環境,無法藉由它自己的定義進行配置,而需要額外的人工作業,就更加難以完成持續整合的建置了。

也許我們的專案尚未需要導入持續整合,但簡化開發環境仍是一個要盡早努力的目標,特別是在專案規模還沒長大前,把自動化的良好開發架構先做好,這麼一來,未來專案變得龐大且複雜時,自動化帶來的好處就會非常明顯,也不會有太多架構轉換的痛苦。
所以一個良好的JavaEE專案架構,應該是一個專案只包含一個項目,也就是只有WebApp。
  1. WebApp
Database要內嵌在專案中,可以考慮在開發及測試階段使用HSQLDB等資料庫引擎,配合Hibernate實作O/RM。這樣在開發及測試階段,就可以有獨立、內嵌的資料庫,可以簡化、自動化處理一些工作。只有在正式上線(Production)時,才使用真正提供服務的資料庫(如MySQL、Oracle或SQL Server)。即使不打算實作O/RM,也可以自行將資料存取層抽離,搭配可以透過script自動建立schema的內嵌資料庫。

但Database並非本文要講述的重點,我們先針對內嵌Container提供一些整理,也就是在網站專案內嵌一個測試專用的網頁伺服器(embeddable web server)。

目前最適合內嵌的JavaEE Container,我推薦的是Jetty,它具有以下的features。
  • Full-featured and standards-based
  • Open source and commercially usable
  • Flexible and extensible
  • Small footprint
  • Embeddable
  • Asynchronous
  • Enterprise scalable
  • Dual licensed under Apache and Eclipse
Jetty剛開始並非想打造全功能的JavaEE Container,而是以輕量化為目標,體積小巧,功能都以高度彈性的模組形式提供,開發者可以自己決定什麼模組要載入,什麼要捨棄,例如有些網站用不到Session功能,就可以不要把Session功能加入處理鏈(chain)。Jetty盡可能不要產生新的物件,所以可以節省記憶體;它提供的非同步(asynchronous)機制,使得高流量的網站(如社群網站),可以大幅降低request/response對系統的消耗。

如果因為Jetty的輕巧,就認為它只是測試用的Container,這個想法就不正確了。Jetty除了在開發、測試階段,是個很好的嵌入式Container,用來應付正式上線、大型企業的需求,也是絕對能夠勝任。它已經內嵌在許多開發環境(如Eclipse)、開發框架(如Grails、GWT、Lift),或許您也已經不知不覺在使用它。

在2009年,Jetty從第7版的發佈開始,遷移到Eclipse基金會。Google在此時也宣佈,旗下的雲端應用開發平台(App Engine),伺服器將從Tomcat改為Jetty(請參考「Google Chose Jetty for App Engine」)。而Yahoo! Hadoop Cluster、VMWare Zimbra,也都是Jetty實際應用的案例。

即使Jetty在大型應用中仍足以勝任,這不代表它變得複雜,在網站專案中加入內嵌的Jetty伺服器,只要以下介紹的簡單步驟。

首先,需要安裝Gradle這個工具,它改良了Ant、Maven等專案自動化工具,只要使用簡單的Groovy語法,就可以把專案所需的編譯、部署及測試等工作自動化,最重要的是能夠自動化處理Java套件的相依性,可以不用麻煩地到處尋找需要的JAR檔。

只要將下載好的Gradle檔案解壓縮,並設定好GRADLE_HOME、PATH等環境變數,在終端機下輸入gradle就可以使用。

對於許多Java專案,幾乎只要裝好JDK+Gradle,就可以不用再裝其他套件,例如Groovy、Scala等,Gradle也都有提供對應的Plugin可以處理。儘管Gradle還是一個很新的專案,未來還有漫長的路要走,但目前用來簡化我們的JavaEE專案開發,已經是是很棒的選擇。

在原有的專案目錄下,假設是一般Eclipse建立的網站專案結構,例如:
/src 放Java原始碼
/WebContent 放網站資料
/WebContent/WEB-INF 放網站設定
/WebContent/classes 放編譯好的類別

這時候我們可以在專案根目錄下,放置一個 build.gradle 設定檔案。

這個Gradle的設定範例,使用jetty plugin,設定了編譯期對servlet-api、jsp-api的相依性,在執行期則需要mysql-connector-java、commons-dbcp(資料庫連接池),並且自訂了srcDirs(原始碼路徑)、classesDir(編譯過的類別路徑),並且設定了Jetty的Context路徑、webAppSourceDirectory(網站資料路徑)以及連接埠8000。

在終端機下,切換到網站根目錄,使用以下的指令就可以完成編譯及啟動測試伺服器。
gradle compileJava
gradle jettyRun

第一次執行的時候,Gradle會依照套件相依性設定,自動下載所需的JAR檔,時間需要久一些,之後除非有修改相依性,否則就會沿用已下載的檔案。

若啟動過程沒有出現錯誤,那就可以用瀏覽器打開「http://localhost:8000/」檢視網站。

結論是,只要裝好JDK及Gradle,透過版本控制系統取得我們的網站專案資料,開發環境不需要再另外安裝維護一個網頁伺服器,就可以透過內嵌的Jetty進行開發及測試,甚至未來也應用在正式上線。由於Gradle本身並非XML設定檔的結構,而是使用Groovy程式語言編寫,這也給我們的專案自動化帶來極大的彈性,可以將自己寫的程式與Gradle提供的任務、Plugin相互搭配。

本文提供的範例,僅是Gradle一個小小的應用,因為Gradle目前能找到的資料有限,希望能拋磚引玉,使更多被繁雜Java開發環境困擾的朋友一同研究。持續改善開發架構,讓Java軟體開發除了熱血、也能多一分輕鬆悠閒。

沒有留言:

張貼留言

lyhcode by lyhcode
歡迎轉載,請務必註明出處!