給Java開發者的Play Framework(2.4)介紹 Part1:Play的優缺點以及適用場景

1. 關於這篇系列

這篇系列不是Play框架的Hello World,由於這樣的文章網上已經有不少。javascript

這篇系列會首先結合實際代碼介紹Play的特色以及適用場景,而後會有幾篇文章介紹Play與Spring,JPA(Hibernate)的集成,以及一些Play應用的最佳實踐, 這期間會在Github上提供一個腳手架項目,方便感興趣的朋友直接動手嘗試。最後會簡單分析Play的部分源碼,幫助你們理解黑盒子的內部機制。html

我水平有限,有錯誤歡迎指出。java

2. Play介紹

Play Framework是一個開源的Web框架,背後商業公司是Typesafe。要介紹Play以前,首先理清Play的兩個不一樣的分支。 Play 1.x 使用Java開發,最新版本是1.3.1,只支持Java項目。從11年開始就進入了維護階段,新項目通常不考慮使用Play1。 Play 2.x 使用Scala和Java開發,同時支持Java和Scala項目。 這裏主要介紹最新的Play2.4 for Java。有一點須要提早說明,雖然Play2主要由Scala開發,可是對於項目中的通常開發人員而言, 使用Play能夠徹底不懂Scala,具體狀況後面會說明。jquery

3. 爲何要了解Play

如今的Web框架或者類庫能夠說是浩如煙海。近十年來,在Web開發領域,JVM陣營的佔有率一直不高, 數據來源(http://hotframeworks.com/#rankings)
這是國外開源項目的數據,相對來講國內Java框架的使用率會高一些。而最近幾年,Ruby和Python在國內的開發羣體也在不斷壯大。 Java框架在Web領域不那麼受歡迎,主要緣由在於開發速度遠落後於其餘的開發框架。對於初創公司而言,快速開發出產品投入市場試錯比花半年打磨出一款功能性能齊備的 應用更加劇要,而對於成熟產品,也須要快速響應頻繁的需求變化,這方面動態語言又更勝一籌。因此說到Web後端框架的技術選型,除非技術團隊有比較深的JVM背景, 不然會傾向於選擇RoR,Django這些框架。git

JVM陣營在Web領域逐漸落後主要有三個緣由:編譯的鍋,技術棧的鍋和語言的鍋。程序員

你們都知道Java源代碼須要編譯以後才能運行,直接結果是每次修改源代碼都須要重啓Web服務器才能看到效果。若是項目比較小類也少,重啓時間還勉強能接受。 我之前參與的一個項目,使用的是WebLogic服務器,Spring容器裏大概有上千個Bean,重啓一次至少得花5分鐘,仍是優化後的結果。工做時間至少有20%花在重啓上了。 雖然如今有JRebel之類的熱加載技術,可是國內使用的相對較少。github

Servlet規範在1997年出現,在當時能夠說是很先進的技術,加上Tomcat的橫空出世,直接促成了JSP的崛起。然而時過境遷,Servlet風光再也不, Web容器存在的必要性也被愈來愈多的人質疑。緣由就在於人爲的將應用與容器剝離, 雖然這種作法本意是好的,可是結果就是給開發測試部署帶來一系列集成的問題,如今愈來愈多的項目開始使用內嵌的Jetty或Tomcat就是一個現實的例子。 Servlet還帶來一個問題,就是有狀態的服務器。一旦使用了Session,服務器就沒法享受到水平擴展的好處了,由此不得不採用Session複製或者粘性Session(Sticky Session)的 方案來解決這個問題,不管採起哪一種方案都會有性能損耗,而且推高了技術成本。Servlet說究竟是Java EE家族的一員,因爲Sun的領導(Oracle背鍋), 從Java EE 5開始,Java EE的角色已經從技術創新者轉換爲跟隨者,這些年基本上能夠說是跟着開源社區的步子在走的,除了政府大單和跨國企業,你很難再看見它的身影了。web

至於語言,其實從JDK8開始,Java已經很好用了。不過從JDK5到JDK8,十年太長,尤爲是在Web。編程

以前Java陣營受累於沒有成熟的快速開發框架,Spring熱衷於提供各類集成方案,但是配置和使用仍是至關的麻煩,直到Spring Boot的出現纔有改善。 不過近幾年出現了一些至關優秀的框架,如DropwizardPlayVert.x。 這篇系列要介紹的Play,經過ClassLoader在源代碼修改的時候動態加載類,解決了修改代碼須要重啓服務器的問題,徹底拋棄了Servlet技術棧,基於Netty實現了本身的 請求響應接口(Request/Result),基於Play的應用就是無狀態的,另外Play處理請求的方式是無阻塞的(Non-Blocking)。Play2在設計的時候借鑑了RoR的許多優勢, 學習Play可以讓你瞭解一些現代化框架的特色,同時可以爲你打開異步編程世界的大門。Promise已經被Scala,JavaScript等語言大量使用,Actor模型也已經遍地開花, 這些你均可以直接在Play中使用,或者你想保持原來的編程風格也徹底沒有問題。後端

4. Play的特性

1. Play2的模板引擎

Play2的模板是很強大而且容易上手的. 相對於Java領域其餘模板引擎(Freemarker, Velocity, JSP, Groovy, etc), 主要有三個特色.
1) 簡單易上手, 沒有JSP裏面繁雜的內置對象和指令, 全部功能都經過方法調用完成.
2) 主流IDE中都支持Play模板的靜態類型檢查, 相似JSP.
3) 支持反向路由.
舉個例子, 通常系統都會有一個固定的頁面佈局, 好比分出頁頭頁尾。若是用JSP或者Velocity之類的模板, 通常都是經過sitemesh+filter或者在每一個頁面include來完成佈局。使用Play模板, 完成這個功能很是容易。 首先定義一個main頁面 main.scala.html:

1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 
@(title: String = "默認標題")(staticFile: Html = Html(""))(content: Html)  <!DOCTYPE html> <html lang="zh-cmn-Hans"> <head>  <meta charset="utf-8" />  <title>@title</title>   </head>  <body>  @header() <-- 頁頭 -->  @navigator() <!-- 導航 -->  @content  <script src="@routes.Assets.versioned("js/jquery-1.11.2.min.js")"></script>  @staticFile 
1
@(title: String = "默認標題")(staticFile: Html = Html(""))(content: Html) 

這一部分是參數聲明,這裏聲明瞭三個參數:title標題, 有默認值;staticFile爲html代碼塊, 能夠傳js等;content爲頁面內容。

1
2 3 
@header() <-- 頁頭 -->  @navigator() <!-- 導航 --> 

這一部分是引用同目錄下的另外兩個頁面:header.scala.html和navigator.scala.html。爲何能這樣引用,由於這些頁面(main,header,navigator)都會被自動 編譯成一個方法(準確地說是一個Scala object,不過這裏先當作方法),因此這裏至關於方法調用。一樣,這個main也會被編譯成方法,其餘頁面能夠調用main來完成佈局, 例如 login.scala.html

1
2 3 4 5 6 7 8 9 
@main() {  <script type="text/javascript">  FG.user.login();  </script> } {  <div class="login width1200">  <!-- login -->  </div> } 

這就是一個簡單的登陸頁面。登陸頁面調用main頁面的方法,第一個參數不傳使用默認標題,第二個參數傳入登陸頁面的js代碼,第三個參數傳入登陸頁面的html代碼。 這樣就完成了頁面佈局, 沒有隨處可見的include, 也沒有暗箱操做的filter, 全部的一切都是方法調用, 是否是很簡單清晰?

靜態類型檢查就不說了, 原本Java的一大優勢(Que Dian)就是類型檢查,因此在Java裏用Freemarker或者Velocity這種模板的作法值得商榷。

反向路由的意思是, 在Play中, 全部的Controller url都配置在一個routes文件中, 例如

1
GET /register @controllers.user.LoginController.registerPage 

以後不管是在Controller裏仍是模板中, 都不用硬編碼url。而是使用routes文件。例如在Controller中使用redirect(routes.LoginController.registerPage())就能實現重定向。 而在模板中使用 <a href="@controllers.routes.LoginController.registerPage()">來指向連接。這種風格就是REST裏的URI模板。

2. 熱部署

這個上面介紹過,不用重啓服務器。

3. 內置dev/prod環境,內置部署腳本

日常開發的時候使用run啓動Play,是跑在dev模式。 Play會定時掃描源碼目錄進行熱更新,而且類都是訪問的時候再加載,提升啓動速度。 使用start啓動項目就運行在prod模式。Play內置dist命令,能夠把全部的文件打包成一個zip,解壓以後直接運行bin目錄下的可執行文件便可啓動項目,除了JDK以外無須任何其餘外部依賴。 這大大減輕了運維成本,同時也可以很方便的進行持續集成(CI)。

4. 使用Play開發的Server大部分能作到Stateless

這個以前也說過,Play拋棄了Servlet/JSP裏Session等概念, 內置沒有提供方法將對象與服務器實例進行綁定(你要使用HashMap存的話Play也沒辦法)。 推薦的作法是使用外部緩存, 好比Redis, Memcached等。可能有人會以爲沒有Session是Play的一個缺點(Play裏的Session和Servlet Session不是一回事), 可是隻要你開發過流量大一點的應用, 你就會理解這點。

5. 好用的配置庫

若是你以前開發過Java項目, 確定寫過**.properties或者管理過一大堆的xml。Java內置庫對properties文件的處理是很弱的,你不得不本身寫一些工具類去進行處理, 並且properties文件還不支持更復雜的語法。Play使用Typesafe Config庫,配置文件使用HOCON格式,默認配置文件爲application.conf。 你能很容易讀取裏面的配置, 而且你也能夠把本身的配置寫在裏面。因此項目中基本不須要使用properties或者xml文件了,除了第三方庫須要的。

6. Play插件

RoR框架之因此好用,主要緣由之一就是圍繞RoR有至關豐富的插件可供選擇,不少業務功能甚至都不須要開發就能實現。Play的插件數量固然相對於RoR仍是要少一些, 不過你遇到的需求基本都有現成的插件可使用。好比發郵件, 受權和驗證, sitemap生成,第三方登陸等等。本身寫一個插件也很簡單。

7. 優秀的測試支持

由於Play誕生的時候TDD已經很火熱,因此Play對測試的支持很是好。 例以下面的幾行代碼就能對Controller進行測試。

1
2 3 
Http.RequestBuilder request = new Http.RequestBuilder().method(POST).uri(routes.LoginController.requestPhoneCode(phone).url()); Result result = route(request); assertThat(result.status(), is(OK)); 

Play還內置了對 Selenium WebDriver的支持,能夠模擬瀏覽器進行測試。如下是官方的例子:

1
2 3 4 5 6 7 8 9 
public class BrowserFunctionalTest extends WithBrowser {   @Test  public void runInBrowser() {  browser.goTo("/");  assertNotNull(browser.$("title").getText());  }  } 

8. 優秀的REST支持

Play2從誕生起就能很容易的支持RESTful風格的架構(由於Play2在設計的時候REST就已經大行其道), 在Play2中實現RESTful API的示例能夠參考Stackoverflow上的這個回答

5. 使用Play過程當中遇到的坑

1. 首次編譯速度過慢

這是Scala的鍋。Scala在編譯過程當中要經歷至少30個步驟, 致使編譯速度至關慢。在個人機器上(Core™ i5-4590 CPU @ 3.30GHz,RAM 8GB),編譯100多個Scala類大約須要1到2分鐘。好在sbt能夠增量編譯, 即首次編譯以後,你再修改代碼,編譯器只會編譯那些它認爲須要編譯的類,編譯幾個類的時候速度很快,基本刷新頁面就能完成。

2. IDE的Scala插件偶爾會誤報錯誤

首先得說明,最適合開發Play項目的IDE是IntelliJ IDEA。如今IDEA最新的Scala插件相比以前的版本,已經有很大的提高。 不過偶爾仍是會出現誤報的狀況,這個問題隨着新版本插件的發佈應該會慢慢解決。

3. Scala和Sbt的學習成本較高

這多是初次接觸Play的用戶遇到的最大障礙。其實對於大多數業務開發人員來講,這不是問題。使用Play for Java版本,項目代碼99%都是Java代碼, 而Sbt相似於Maven,一旦項目搭建好後不須要過多接觸,只要學會幾個經常使用的命令就能夠了,例如project root(切換項目), run(啓動服務器在dev模式)。 咱們團隊大部分紅員以前都沒有接觸過Scala和Play,通過一兩週的磨合期以後都能很順利的使用Play進行開發了。

4. Play的API變化速度比較快

Play的版本號遵循Semantic Versioning,不一樣主版本的API變化很是大,好比Play1和Play2就是兩個不一樣的框架。 而副版本之間API也會有一些變化,並且不必定徹底向後兼容。例如使用Play2.3.x的項目在升級到2.4的時候,須要按照官方提供的遷移手冊進行代碼修改, 否則是運行不了的。這對於其餘背景的開發者來講可能比較容易理解,可是若是是一直習慣於使用Spring MVC或Struts2的話,可能會對這點感到不適。

6.總結

Play2能夠算是一個現代化的框架,吸取了RoR諸多優勢,同時又解決了Java開發中的一些痛點,在國外已經被大量使用。參見 數據來源(http://www.infoq.com/research/jvm-web-frameworks)

Play和Spring MVC的定位有些類似,可是比Spring MVC提供更豐富的功能,和Web有關的項目均可以使用Play。可是若是要用好Play,對團隊有必定的要求。

首先,你的團隊應該不是墨守成規的團隊。大部分人都懼怕變化,這是不爭的事實。JDK的發展緩慢加上國內的技術氛圍,着實讓Java開發人員過了幾年的舒服日子。 你若是是05年學會了ibatis和Spring,而後這十年去環遊世界了,在15年你照樣能輕鬆找到一份待遇還算能夠的工做。然而事情已經開始發生變化,不會學習可能會被淘汰。

其次,你的團隊應該重視工做效率和質量,而且有時間作出改進。國內不少團隊信奉的是人海戰術。以低薪聘請大量不合格的開發人員來開發業務功能, 而不是注重單人的工做效率和質量,不少項目的加班和延期都源於此。這樣的團隊就不適合用Play。很難想象天天都要加班去應付工做的團隊有時間打磨升級本身的工具和技能。 可是反過來低效率的工具和技能又拖累了本身的工做效率,這是一個惡性循環。

最後,團隊中須要有人對Scala和Sbt有必定的瞭解。雖然Play有Java版本可使用,可是若是不會Scala和Sbt,在搭建環境,使用一些高級功能(如Filter)的時候可能會遇到麻煩。

 

  碼農必需要加班?NO!

  知道碼農們都想擺脫加班狗、外賣臉的稱號,因此咱們來了!

  咱們作了一個能讓程序員之間共享知識技能的APP,以爲能夠顛覆程序員的工做方
式!

  有人說咱們癡心妄想,但咱們不那麼認爲。

  爲了能煽爛說咱們癡心妄想的人的臉,如今咱們急需程序員業內的牛嗶-人物來給
咱們「號脈」!「診斷費」豐厚!畢竟咱們不差錢兒,只是想作到最好!

  圈圈字典中講到,牛嗶-人物是指羣成員數高於1000人的QQ羣主或關注人數高於
2000人的貼吧吧主或粉絲人數高於10000人的微博博主或成員數高於2000主題貼的版主
或單帖閱讀量高於2000博客主或人脈超級廣的圈內紅人。

  對於未能達標的將來大神們,咱們只能含淚表示:蜀黍,我們來日方長,此次暫
時不約好嗎?待他日你立地成神,我必生死相依!

  來?仍是不來?

  圈圈互動 接頭暗號:1955246408 (QQ)

相關文章
相關標籤/搜索