Play Framework2.1源码分析

Stella981
• 阅读 427

转载请注明出处,保持署名 _ 作者:joymufeng_


1. 介绍

大家翘首以盼的Play2.1终于发布了,目前可用版本是Play 2.1-RC4。在此感谢Play!开发团队付出的辛勤努力!Play2.1以后版本中将会加入导出符合Servlet3.1规范的War包功能,相信大家对这个功能也很期待。废话少说,回归正题,先了解一下,Play2.1中究竟有哪些新的变化:

  • Scala升级到2.10版本

与时俱进,这是Play!框架的一贯作风

  • scala.concurrent.Future

这是scala 2.10中最激动人心的API,并发中的生产者/消费者问题,寥寥几行代码就搞定,真心钦佩!

  • 模块化

模块化使得开发者可以定制自己的框架。比如你可以将Play框架定制成一个高性能的、异步Http Server。

  • 允许Play项目模块化开发
  • 异步执行的代码可以操作Http.Context
  • 为Java开发者提供更好的线程模型
  • 开发者可以控制控制器类的实例化,更容易和Spring框架集成
  • 全新的Scala JSON API
  • 全新的Filter API和CSRF保护
  • RequireJS
  • 改进内容协商

详细信息请参考:http://www.playframework.org/documentation/2.1-RC3/Highlights

Play2.1的架构图如下,核心组件仍然是Netty和AKKA,

    Play Framework2.1源码分析

线程是系统最宝贵的资源,也是影响系统性能最关键的因素。下面本文主要围绕“线程策略”这个主题,通过源码分析Play2.1的架构设计。

2. Netty线程策略

2.1 源码分析

Netty是一个异步的、基于事件驱动的高性能网络应用框架。非常适合编写Web服务器应用。在Play2.1中,Netty的入口类是play.core.server.NettyServer,该类中创建NioServerSocketChannelFactory代码如下:

new org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory(
      Executors.newCachedThreadPool(NamedThreadFactory("netty-boss")),
      Executors.newCachedThreadPool(NamedThreadFactory("netty-worker"))))

这里使用 Executors的newCachedThreadPool方法创建线程池,该方法的文档描述如下: 

   Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available. These pools will typically improve the performance of programs that execute many short-lived asynchronous tasks. Calls to execute will reuse previously constructed threads if available. If no existing thread is available, a new thread will be created and added to the pool. Threads that have not been used for sixty seconds are terminated and removed from the cache. Thus, a pool that remains idle for long enough will not consume any resources. Note that pools with similar properties but different details (for example, timeout parameters) may be created usingThreadPoolExecutor constructors.

从文档描述中可以看出,newCachedThreadPool适合于大量短时间、异步任务的执行,在执行任务时,会重用之前创建的线程,如果没有可用的,则创建一个新的线程,并加入到线程池中。如果线程空闲超过60秒,则会被终止,并从线程池中移除。newCachedThreadPool的这些特性,刚好满足Netty的异步、事件驱动的需求。

2.2 Netty线程策略总结

Netty中处理ServerSocketChannel的"Boss threads", 和处理客户端Channel的"Worker threads"都使用newCachedThreadPool,即根据需要创建新的线程。"Boss threads"的数量取决于Netty绑定的端口个数,例如80和443端口;"Worker threads"的数量则取决于客户端请求数量。当客户端请求逐渐增多时,系统将变的不可控。

3. AKKA线程策略


AKKA中的actors实际执行的线程环境是由其关联的dispatcher管理的。所以这里我们只关注dispatcher的实现。 Play2.1中AKKA的线程策略和2.0版本相比,区别比较大。在play2.0中,actions、promises和websockets actors分别使用各自的dispatcher,其它actors使用默认的default-dispatcher。而在Play2.1中,所有的AKKA actors都使用默认的default-dispatcher,其配置如下:

default-dispatcher = {
                fork-join-executor {  
                    parallelism-min = 8
                    parallelism-factor = 1.0
                    parallelism-max = 24
                }
            }

从上面的配置可以看出,默认情况下,default-dispatcher只使用8个线程。

4. Play框架核心API的线程策略

  为了保证快速处理客户端请求,Play中很多操作都是异步完成的。这些异步操作的执行环境是由play.core.Execution提供的。该类中创建了internalContext: scala.concurrent.ExecutionContext, 作为隐式的ExecutionContext, 线程池大小为processors个数,即CPU的总核数。

lazy val internalContext: scala.concurrent.ExecutionContext = {
    val numberOfThreads = play.api.Play.maybeApplication.map(_.configuration.getInt("internal-threadpool-size")).flatten.getOrElse(Runtime.getRuntime.availableProcessors)
    ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(numberOfThreads, NamedThreadFactory("play-internal-execution-context")))
}

在Play2.1的核心API中,用到这个隐式参数的API大体如下:

Play Framework2.1源码分析

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
35岁是技术人的天花板吗?
35岁是技术人的天花板吗?我非常不认同“35岁现象”,人类没有那么脆弱,人类的智力不会说是35岁之后就停止发展,更不是说35岁之后就没有机会了。马云35岁还在教书,任正非35岁还在工厂上班。为什么技术人员到35岁就应该退役了呢?所以35岁根本就不是一个问题,我今年已经37岁了,我发现我才刚刚找到自己的节奏,刚刚上路。
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
4个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这