给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)

相关文章
相关标签/搜索