個人看到對比play1.x和play2.x比較的文章中,寫的最深入,最清晰的一個。轉自:http://freewind.me/blog/20120728/965.html
為了方便群中的Play初學者們,寫了一篇入門引導,以幫助初學者盡快了解Play。本文之前發在另一個網站,因為覺得有些不便,還是轉到博客上。
歡迎來到play的世界,在這里你將體驗到與傳統SSH開發網站不一樣的感受。我將把我學習play的感受與經驗分享給大家,希望能對大家(特別是初學者)有所幫助。
Play是一個非常有創造力、讓人眼前一亮的Java web開發框架。它把網站開發中常見的繁瑣的任務,以各種突破常規的方式簡化,“不要重復你自己”,讓人在開發過程中有一種享受的感覺。使用Play實現功能,有時候簡單地讓人難以相信(對於長期使用SSH的人來說尤其明顯)。
在play的google group中,曾經有人說,當地要舉辦一次編程大賽,他將使用play參賽。每個參賽隊可使用任何語言和框架,在6小時內實現指定的功能。結果他們勝利了,打敗了Ruby on rails隊。使用Play開發網站,在不使用各種第三方插件的情況下(Rails強項),開發效率與Rails在同一級別。
這里將介紹一些最讓我印象深刻的特性:
-
修改不用重啟:這是play最為吸引人的一點。修改任何java或模板代碼,都不需要重啟server,直接在瀏覽器中刷新即可看到最新效果。這曾是多少Javaer夢想的功能。結合livereload等工具,可以實現光標不離開編輯器就能實時看到最終頁面效果的功能。
-
無狀態:Play是無狀態的,不保存與客戶端相關的數據,比如它的session是以加密方式保存在cookie中的。這意味着play程序擁有良好的擴展性,比如當訪問壓力過大時,可以簡單地多啟動幾個play實例即可(使用不同端口+反向代理)。由傳統的Servlet程序則需要考慮session同步等問題。
-
代碼增強:代碼增強是Play的重點功能,也是它最富於創新力的地方。在play導入我們所寫的java源代碼時,會使用javassist這個工具,根據內置或第三方的插件的要求修改字節碼,實現一些原本無法實現的功能。比如充血模型,生成getter/setter,根據參數名自動從request中取參數,根據參數名自動向template中設置參數等。我們可以省去很多不必要的代碼和為因Java語言限制而存在的設計模式,寫出簡潔清晰的代碼。由於“代碼增強”的存在,使得play與眾不同。
-
模板中方法調用與url的自動轉換:在play的模板中,需要與后台交互(比如跳轉頁面)時很少寫url,因為我們可以直接調用相應的Action和參數,由Play根據routes文件中的定義生成相應的url。當url更改時,直接修改routes文件即可,不需要動模板文件。當我們寫錯(如方法名)時,play會自動提示編譯錯誤。該功能讓我們重構url時非常輕松。
-
對restful api的良好支持:在routes文件中,通過簡單的規則就可以定義出restful api的接口。通過在server端生成jsRoutes(包含了restful api的信息),在瀏覽器端可以方便地使用ajax與后台交互。
-
內置基於netty的web服務器:play內嵌了基於netty的高性能服務器,只需要一條命令即可運行起來,簡單而強勁,推薦使用。如果因為服務器限制而必須使用傳統的servlet服務器的話,可將play程序打包為war部署。
Play的版本
Play當前的版本有點亂,不同版本之間差別還相當大,這常常讓初學者一頭霧水。Play目前可分為三個版本,它們之間沒有誰比誰好,只有誰比誰適合。大家可根據自己的實際情況來選擇合適的版本來學習。
首先是Play的成名之作:Play1
Play1.x是成名之作。它是一個Java開發框架,使用python作為構建系統。內置了Jpa(Hibernate)和基於groovy的模板系統。它大量使用了代碼增強,提供了大量魔術般的功能,以提高程序員的開發效率和代碼的簡潔性。它編譯速度快,代碼簡潔,讓人開發時非常享受。Play1當前最新版本為1.2.5,它是三者間最為成熟的一個版本,擁有大量成熟的第三方模塊供使用。這里值得一提的是群友green開發了大量基於play1的優秀插件,如rythm/play-morphia等,進一步提高了play的性能及開發效率。雖然play1目前已處於維護狀態,但如果你需要在近期開發傳統的信息管理類網站,它仍然是最佳選擇。
關於Play2
幾個月前,Play1的開發者加入了typesafe.com,並且play作為其官方web框架。typesafe是一個力推scala的公司,所以新推出的play2,實際上是將scala作為第一開發語言的。比如play2中使用的新構建工具sbt,是scala的標准構建工具;play2中很多底層代碼都是用scala寫的,由Java來調用;play2的默認模板引擎,也是基於scala的。在play2中,處處可見scala的痕跡。但play2也同時提供了java api,以吸引廣大的Java開發者。由於Scala與Java在語言特性與風格上的巨大差別,play2-scala與play2-java,在很多地方都不同。
play2相對於play1,不是一次簡單的版本升級,而是幾乎重寫了全部代碼。Play2與Play1在很多方面都不同,不能通用。也許它本來就不該叫play2的,它與play1的區別,如同struts2與struts1的區別(struts2其實是由另一個叫webwork的框架改名而來)。Play開發團隊從商業利益上的考慮作出的決定(以及某種程度的不負責任),曾經在play社區中引起激烈爭論,大批play1用戶表達了自己的不滿和對play2的失望。
Play2在開發風格上與Play1有所不同。如同typesafe公司名稱所示,Play2在最大程度的利用編譯器的檢查,以求更加穩定可靠。在Play1中一些追求簡潔的魔術代碼,在Play2中取消了,相反要使用一些略顯繁瑣的代碼來實現相同功能。同時因為scala相當慢的編譯速度,讓熱修改后生效的時間大大延長,有時候難以忍受(在play1中1秒以內,play2中要5秒以上)。所以很多從play1轉向play2的用戶都非常不適應,拒絕轉向play2。
由於Play2的倉促推出,當前的2.0.2版不論在功能上還是穩定性都存在相當多的問題,插件生態系統也沒有成熟(Play1的插件不能在Play2上使用)。所以當前直接在生產系統中使用它還是有一定風險的,最好再等幾個月。
不論如何,Play2是官方支持,目前所有的開發活動都基於它,它是未來的趨勢。它重新組織的代碼結構與API,相比1來說,也要精致很多。相信現在存在的各種問題在未來會慢慢解決,只是需要一段時間。
Play2的賣點是並發,因為它底層使用了scala中的akka庫,對於開發實時網站程序比較有優勢。但對於傳統的信息系統類網站,也許Play2很難達到Play1的程度。個人認為,對於以開發信息系統為主的團隊,使用Play1在各方面來講,都會是更好的選擇。
對於認為新版一定好於舊版,或敢於嘗鮮而選擇了Play2的朋友,馬上要面臨一個新的問題:
是用Play2-Scala還是Play2-Java呢?
個人認為,這個選擇還是比較簡單的。如果你是Scala程序員,來尋找Scala下的web框架,就選Play2-Scala。它比lift簡單易學,容易上手。如果你是Java程序員,或者主要以Java項目為主,請選擇Play2-Java。
雖然Scala在宣傳上總是以“更好的Java“來作為賣點,但它實際上是一門與Java相差非常大的語言。在語言風格上,Scala融合面向對象與函數式,強調數據的不變性,這都與Java不同。在難度上,Scala要比Java難很多,函數式編程和類型系統會讓很多Java程序員止步,通常在六七年的編程經驗后再學習Scala是比較靠譜的選擇。
另外,雖然兩者都是JVM上的語言,但它們之間是有縫的,調用對方的庫經常會遇到各種各樣的問題。比如你想在Scala上使用java的jpa/ebean/morphia等,會非常麻煩。但scala自己又沒有一個足夠成熟好用的orm,這可能是阻止你使用Play2-Scala的一個重要原因。
所以,還是如前面所說,Scala程序員選Play2-Scala,Java程序員選Play2-Java。
Play2-Scala
Play2-Scala相對於Scala上的另一個成熟web框架lift來說,優勢在於簡單易學、有typesafe官方支持,前途光明。同時對於以restful api作為主要目的的程序來說,Play2提供的routes相當好用。劣勢在於不如lift成熟,生態系統不如lift。在某些時候,Play2的MVC不如Lift的View-First好用。
Play2使用了sbt,底層是akka,模板層基於scala,orm是Play自己開發的一個叫anorm的持久層。anorm的特點拋棄orm,直接使用jdbc,使用預定義的parser把結果集轉為對象。Anorm初看起來比較吸引人,但在實際使用過程中,異常繁瑣。對數據庫字段的一次修改,往往要牽扯到幾個地方,動不動就出錯,同時再加上scala奇慢無比的編譯速度,極易讓人心情煩躁。所以也有人嘗試在play2中使用squerl,好在很容易集成。當然還是讓我們期待typesafe正在開發的新orm:slick。
對於Scala程序員來說,Play2-Scala是一個比較好的選擇,不妨一試。
注意,如果你使用Play2-Scala,想使用Play2中提供的JPA/Ebean時請小心。由於Play2在代碼增強時,只增強Java代碼,這將導致從Scala中調用它們時出現問題,所以最好選擇scala中的orm。
Play2-Java
對於Java程序員來說,還是用Play2-Java比較順手。雖然相比Play1要繁瑣一些,但對於SSH等,還是要簡潔很多。Play2中Java的api與Scala的api不在同一個包下,要注意不要引用錯了。
對於controller和action,Play2與play1的結構基本相同,依然采用靜態方法,但需要返回一個Result。注意的是,Action中的參數,只能匹配在routes中的url定義中出現的參數,而不像play1那樣,還能匹配任意query參數和post參數。
Orm方面,同時提供了JPA(hibernate)和Ebean。我個人比較推薦Ebean,相對於hibernate,它的api更加簡單,不易出錯,因為它是用jdbc的思路。在官方下載包里有一份100多頁的pdf文檔,看完就差不多了,用起來麻煩絕對比hibernate少太多。我在Play1中就通過第三方的插件使用Ebean,效果很好。也許只有一種情況不能用它,因為它不支持sql server。
Play2基於scala的模板層,對於Java開發者來說是不太方便的。兩點原因:
- Scala的語法與Java不同,雖然在模板中已經盡量簡化了,但難免還是會遇到一些不好下手的問題。
- 模板將被轉化為Scala代碼進行編譯。如前文所說,Play2對於Scala代碼不會進行增強,所以在模板中調用Java類可能會有問題。比如直接調用
@user.articles
,它不會像在Java中那樣被替換為user.getArticles
,而是直接調用user.articles
字段。由於代碼增強通常是在getter/setter上進行的,所以這樣可能拿不到數據。如果想解決此類lazy loading的問題,我們必須在model中使用傳統的javabean方式顯式聲明getter/setter,然后在模板層中調用@user.getArticles
,相當繁瑣。
所以在Play2官方推出基於java的模板前,我推薦使用兩個第三方模板插件。一是faster groovy template,二是japid,它們都已經支持Play2,且不會有上述問題(Japid待測)。
另外,對於不喜歡Java語法但又不想用scala的同學,可嘗試xtend。xtend代碼要比Java舒服一些,而且直接生成java源代碼,不存在編譯等問題。
Play存在的問題
雖然Play在很多方面給我們帶來的方便,但難免也會有一些問題需要注意,這里簡單提一下。
Play1
Play1主要存在的問題有三個:
-
與某些第三方庫結合使用時,必須寫插件。比如morphia, ebean等。因為Play1需要對我們的Java源代碼進行增強,而這些庫也需要對字節碼進行增強。如果不寫插件處理classloader及字節碼,會出現無法運行的情況。
-
使用javassist修改字節碼比較繁瑣易錯。當Play用到一定程度,難免會需要寫自己的插件,對字節碼進行增強以實現特殊功能。但使用Javassist來修改字節碼,還是一件比較容易出錯的工作,經常要花大量的時間在調試上。特別寫的插件需要先打包,才能在其它項目中使用,看到效果,非常費時。(如果有簡潔方法請告訴我)
-
停止開發,只維護。官方現在只開發Play2,對於Play1不再開發新功能,只維護。如果想要增加新功能,只能靠自己或第三方插件。
Play2
Play2主要有以下幾個問題:
-
目前不夠成熟。不論是框架本身還是插件系統,都不太成熟。如果在大型項目中使用,必須自己實現很多功能,以及整合很多第三方庫。
-
使用sbt作為構建系統。sbt用起來也相當繁瑣,要花不少時間才能熟練使用。而且,如果想開發自己的構建插件,還需要學習scala和sbt那些變態的api。這對於Java程序員來說,難度實在太大。
-
Play2-scala缺少一個好用的orm,Play2-java缺少一個好用的模板層
-
Play2在某些方面與Play1相比顯得繁瑣,讓用慣Play1的人不易適應。
-
Scala緩慢的編譯速度,常常讓人難以忍受,要求用戶的電腦配置比較高。