这篇系列不是Play框架的Hello World,因为这样的文章网上已经有很是多。javascript
这篇系列会首先结合实际代码介绍Play的特色以及适用场景。而后会有几篇文章介绍Play与Spring,JPA(Hibernate)的集成,以及一些Play应用的最佳实践。 这期间会在Github上提供一个脚手架项目。方便感兴趣的朋友直接动手尝试。html
最后会简单分析Play的部分源码。帮助你们理解黑盒子的内部机制。java
我水平有限,有错误欢迎指出。jquery
Play Framework是一个开源的Web框架。背后商业公司是Typesafe。git
要介绍Play以前。首先理清Play的两个不一样的分支。 Play 1.x 使用Java开发。最新版本号是1.3.1,仅仅支持Java项目。github
从11年開始就进入了维护阶段,新项目通常不考虑使用Play1。web
Play 2.x 使用Scala和Java开发。同一时候支持Java和Scala项目。 这里主要介绍最新的Play2.4 for Java。有一点需要提早说明,尽管Play2主要由Scala开发,但是对于项目中的通常开发者而言, 使用Play可以全然不懂Scala。详细状况后面会说明。编程
现在的Web框架或者类库可以说是浩如烟海。近十年来,在Web开发领域,JVM阵营的占有率一直不高。 数据来源(http://hotframeworks.com/#rankings)
这是国外开源项目的数据,相对来讲国内Java框架的使用率会高一些。而近期几年,Ruby和Python在国内的开发群体也在不断壮大。后端
Java框架在Web领域不那么受欢迎,主要缘由在于开发速度远落后于其它的开发框架。对于初创公司而言,高速开发出产品投入市场试错比花半年打磨出一款功能性能齐备的 应用更加剧要,而对于成熟产品,也需要高速响应频繁的需求变化,这方面动态语言又更胜一筹。因此说到Web后端框架的技术选型,除非技术团队有比較深的JVM背景。 不然会倾向于选择RoR,Django这些框架。浏览器
JVM阵营在Web领域逐渐落后主要有三个缘由:编译的锅,技术栈的锅和语言的锅。
你们都知道Java源码需要编译以后才干执行,直接结果是每次改动源码都需要从新启动Webserver才干看到效果。
假设项目比較小类也少,从新启动时间还勉强能接受。
我曾经參与的一个项目,使用的是WebLogicserver。Spring容器里大概有上千个Bean,从新启动一次至少得花5分钟。仍是优化后的结果。工做时间至少有20%花在从新启动上了。 尽管现在有JRebel之类的热载入技术,但是国内使用的相对较少。
Servlet规范在1997年出现,在当时可以说是很是先进的技术。加上Tomcat的横空出世。直接促成了JSP的崛起。然而时过境迁,Servlet风光再也不。 Web容器存在的必要性也被愈来愈多的人质疑。
缘由就在于人为的将应用与容器剥离, 尽管这样的作法本意是好的,但是结果就是给开发測试部署带来一系列集成的问题,现在愈来愈多的项目開始使用内嵌的Jetty或Tomcat就是一个现实的样例。 Servlet还带来一个问题,就是有状态的server。一旦使用了Session,server就没法享受到水平扩展的长处了。由此不得不採用Session复制或者粘性Session(Sticky Session)的 方案来解决问题,无论採取哪一种方案都会有性能损耗。并且推高了技术成本。
Servlet说到底是Java EE家族的一员。因为Sun的领导(Oracle背锅), 从Java EE 5開始。Java EE的角色已经从技术创新者转换为尾随者,这些年基本上可以说是跟着开源社区的步子在走的。除了政府大单和跨国企业,你很是难再看见它的身影了。
至于语言。事实上从JDK8開始,Java已经很是好用了。
只是从JDK5到JDK8。十年太长。尤为是在Web。
以前Java阵营受累于没有成熟的高速开发框架。Spring热衷于提供各类集成方案,但是配置和使用仍是至关的麻烦,直到Spring Boot的出现才有改善。 只是近几年出现了一些至关优秀的框架,如Dropwizard,Play。Vert.x。 这篇系列要介绍的Play,经过ClassLoader在源码改动的时候动态载入类,攻克了改动代码需要从新启动server的问题,全然抛弃了Servlet技术栈,基于Netty实现了本身的 请求响应接口(Request/Result),基于Play的应用就是无状态的,另外Play处理请求的方式是无堵塞的(Non-Blocking)。Play2在设计的时候借鉴了RoR的不少长处。 学习Play可以让你了解一些现代化框架的特色,同一时候可以为你打开异步编程世界的大门。Promise已经被Scala,JavaScript等语言大量使用,Actor模型也已经遍地开花。 这些你都可以直接在Play中使用。或者你想保持原来的编程风格也全然没有问题。
Play2的模板是很是强大并且easy上手的. 相对于Java领域其它模板引擎(Freemarker, Velocity, JSP, Groovy, etc), 主要有三个特色.
1) 简单易上手, 没有JSP里面繁杂的内置对象和指令, 所有功能都经过方法调用完毕.
2) 主流IDE中都支持Play模板的静态类型检查, 类似JSP.
3) 支持反向路由.
举个样例, 通常系统都会有一个固定的页面布局, 比方分出页头页尾。假设用JSP或者Velocity之类的模板。 通常都是经过sitemesh+filter或者在每个页面include来完毕布局。使用Play模板, 完毕这个功能很是easy。 首先定义一个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模板。
这个上面介绍过。不用从新启动server。
寻常开发的时候使用run启动Play,是跑在dev模式。 Play会定时扫描源码文件夹进行热更新。并且类都是訪问的时候再载入,提升启动速度。 使用start启动项目就执行在prod模式。Play内置dist命令。可以把所有的文件打包成一个zip,解压以后直接执行bin文件夹下的可执行文件就能够启动项目。除了JDK以外无须不论什么其它外部依赖。
这大大减轻了运维成本,同一时候也可以很是方便的进行持续集成(CI)。
这个以前也说过。Play抛弃了Servlet/JSP里Session等概念, 内置没有提供方法将对象与server实例进行绑定(你要使用HashMap存的话Play也没办法)。 推荐的作法是使用外部缓存, 比方Redis, Memcached等。可能有人会以为没有Session是Play的一个缺点(Play里的Session和Servlet Session不是一回事), 但是仅仅要你开发过流量大一点的应用, 你就会理解这点。
假设你以前开发过Java项目, 确定写过**.properties或者管理过一大堆的xml。Java内置库对properties文件的处理是很是弱的,你不得不本身写一些工具类去进行处理, 并且properties文件还不支持更复杂的语法。
Play使用Typesafe Config库,配置文件使用HOCON格式,默认配置文件为application.conf。
你能很是easy读取里面的配置, 并且你也可以把本身的配置写在里面。
因此项目中基本不需要使用properties或者xml文件了,除了第三方库需要的。
RoR框架之因此好用。主要缘由之中的一个就是环绕RoR有至关丰富的插件可供选择,很是多业务功能甚至都不需要开发就能实现。
Play的插件数量固然相对于RoR仍是要少一些, 只是你遇到的需求基本都有现成的插件可以使用。比方发邮件, 受权和验证, sitemap生成,第三方登陆等等。
本身写一个插件也很是简单。
因为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()); } } |
Play2从诞生起就能很是easy的支持RESTful风格的架构(因为Play2在设计的时候REST就已经大行其道), 在Play2中实现RESTful API的演示样例可以參考Stackoverflow上的这个回答
这是Scala的锅。Scala在编译过程当中要经历至少30个步骤, 致使编译速度至关慢。在个人机器上(Core™ i5-4590 CPU @ 3.30GHz,RAM 8GB)。编译100多个Scala类大约需要1到2分钟。
好在sbt可以增量编译, 即首次编译以后,你再改动代码。编译器仅仅会编译那些它以为需要编译的类,编译几个类的时候速度很是快,基本刷新页面就能完毕。
首先得说明。最适合开发Play项目的IDE是IntelliJ IDEA。
现在IDEA最新的Scala插件相比以前的版本号,已经有很是大的提高。 只是偶尔仍是会出现误报的状况,这个问题随着新版本号插件的公布应该会慢慢解决。
这多是初次接触Play的用户遇到的最大障碍。事实上对于大多数业务开发者来讲。这不是问题。使用Play for Java版本号,项目代码99%都是Java代码, 而Sbt类似于Maven,一旦项目搭建好后不需要过多接触,仅仅要学会几个常用的命令就可以了,好比project root(切换项目), run(启动server在dev模式)。
咱们团队大部分红员以前都没有接触过Scala和Play,通过一两周的磨合期以后都能很是顺利的使用Play进行开发了。
Play的版本号号遵循Semantic Versioning,不一样主版本号的API变化很是大。比方Play1和Play2就是两个不一样的框架。 而副版本号之间API也会有一些变化,并且不必定全然向后兼容。好比使用Play2.3.x的项目在升级到2.4的时候,需要依照官方提供的迁移手冊进行代码改动, 否则是执行不了的。
这对于其它背景的开发者来讲可能比較easy理解,但是假设是一直习惯于使用Spring MVC或Struts2的话,可能会对这点感到不适。
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)的时候可能会遇到麻烦。
下篇我会介绍Play和Spring还有JPA(Hibernate)的集成,毕竟Spring在大部分Java项目仍是主流。有问题和建议欢迎指出。