SlideShare a Scribd company logo
1 of 88
Download to read offline
Playframework
1
1.
2.
3.
4.
3 4
4
3 20:00
2
3
@tanacasino
Scala 2 Eucalytpus
OpenStack
GitBucket (Committer)
4
GitHub
5
6
7
documentation
framework
templates
Play
Lightbend HP
play-scala
8
framework/src
build-link play-functional play-netty-utils
fork-run play-integration-test play-server
fork-run-protocol play-java play-specs2
iteratees play-java-jdbc play-streams
play play-java-jpa play-test
play-akka-http-server play-java-ws play-ws
play-cache play-jdbc routes-compiler
play-datacommons play-jdbc-api run-support
play-docs play-jdbc-evolutions sbt-fork-run-plugin
play-docs-sbt-plugin play-json sbt-plugin
play-exceptions play-logback
play-filters-helpers play-netty-server
9
10
1.
2. Action Controller
3. Json
4. Applicative
11
12
main
def main(args: Array[String]): Unit
13
main
ag 'def main(' src
3
fork-run sbt
src/fork-run/src/main/scala/play/forkrun/ForkRun.scala
28: def main(args: Array[String]): Unit = {
src/play-netty-server/src/main/scala/play/core/server/NettyServer.scala
298: def main(args: Array[String]) {
src/play-server/src/main/scala/play/core/server/ProdServerStart.scala
20: def main(args: Array[String]) {
14
NettyServer
def main(args: Array[String]) {
System.err.println(
s"NettyServer.main is deprecated. 
Please start your Play server with the 
${ProdServerStart.getClass.getName}.main."
)
ProdServerStart.main(args)
}
ProdServerStart
15
main grep
play-scala
sbt dist
ProdServerStart
declare -a app_mainclass=("play.core.server.ProdServerStart")
# java -jar play.core.server.ProdServerStart
16
framework/src/play-
server/src/main/scala/play/core/server/ProdServe
rStart.scala
2
object ProdServerStart {
/**
* Start a prod mode server from the command line.
*/
def main(args: Array[String]) {
val process = new RealServerProcess(args)
start(process)
}
// ...
} 17
RealServerProcess
ServerProcess JVM
/**
* Abstracts a JVM process so it can be mocked for testing or to
* isolate pseudo-processes within a VM. Code using this class
* should use the methods in this class instead of methods like
* `System.getProperties()`, `System.exit()`, etc.
*/
trait ServerProcess
class RealServerProcess(
val args: Seq[String]
) extends ServerProcess
18
ServerProcess
trait ServerProcess {
/** The ClassLoader that should be used */
def classLoader: ClassLoader
/** The command line arguments the process as invoked with */
def args: Seq[String]
/** The process's system properties */
def properties: Properties
/** Helper for getting properties */
final def prop(name: String): Option[String] = Option(properties.getProp
/** The process's id */
def pid: Option[String]
/** Add a hook to run when the process shuts down */
def addShutdownHook(hook: => Unit): Unit
/** Exit the process with a message and optional cause and return code *
def exit(message: String, cause: Option[Throwable] = None, returnCode:
}
19
RealServerProcess
pid
class RealServerProcess(val args: Seq[String]) extends ServerProcess
def classLoader: ClassLoader =
Thread.currentThread.getContextClassLoader
def properties: Properties = System.getProperties
def pid: Option[String] = ManagementFactory.getRuntimeMXBean
.getName.split('@').headOption
def addShutdownHook(hook: => Unit): Unit = {
Runtime.getRuntime.addShutdownHook(new Thread {
override def run() = hook
})
}
def exit(message: String, cause: Option[Throwable] = None, returnCode:
/* ... */
}
}
20
ProdServerStart#start
def main(args: Array[String]): Unit = {
val process = new RealServerProcess(args)
//
start(process)
}
// 4
def start(process: ServerProcess): ServerWithStop = {
try {
// 1. Read settings
val config: ServerConfig = readServerConfigSettings(process)
// 2. Create a PID file before we do any real work
val pidFile = createPidFile(process, config.configuration)
// 3. Start the application
val application: Application = { /* */ }
Play.start(application)
// 4. Start the server
val serverProvider: ServerProvider = ServerProvider.fromConfiguration(
val server = serverProvider.createServer(config, application)
// ...
}
21
ProdServerStart#start
1.
2. PID(Process ID)
3. play.api.Application
4. HTTP
22
1. src
!(option).isDefined (option).isEmpty
def readServerConfigSettings(process: ServerProcess): ServerConfig = {
val configuration: Configuration = { /* */ }
val rootDir: File = { /* */ }
def parsePort(portType: String): Option[Int] = {
// configuration http/https parse
}
val httpPort = parsePort("http")
val httpsPort = parsePort("https")
if (!(httpPort orElse httpsPort).isDefined) throw ServerStartException
val address = configuration.getString("play.server.http.address")
.getOrElse("0.0.0.0")
ServerConfig(/* */)
}
23
{} rootDirArg
val configuration: Configuration = {
// rootDir Some(java.io.File)
val rootDirArg: Option[File] =
process.args.headOption.map(new File(_))
// Map.empty
// play.server.dir
// "play.server.dir" -> "${dir.getAbsolutePath}" Map
val rootDirConfig = rootDirArg.fold(Map.empty[String, String])
(dir => ServerConfig.rootDirConfig(dir))
// Configuration .
Configuration.load(
process.classLoader, process.properties, rootDirConfig, true
)
}
24
play.api.Con guration
object Configuration {
private[play] def load(
classLoader: ClassLoader,
properties: Properties,
directSettings: Map[String, AnyRef],
allowMissingApplicationConf: Boolean): Configuration = {
try {
// 1. SystemProperty
val systemPropertyConfig = /* */
// 2. Map[String, String]
val directConfig: Config = ConfigFactory.parseMap(directSettings.asJ
// 3. conf/application.conf
val applicationConfig: Config = /* */
// 4. play overrides conf
val playOverridesConfig: Config = ConfigFactory.parseResources(class
// 5. reference.conf
val referenceConfig: Config = ConfigFactory.parseResources(classLoad
// ... 25
5
1. SystemProperty (System.getProperty)
2. DirectCon g:
3. conf/application.conf )
4. play overrides con g
Akka Play
5. reference.conf
Play
26
Combine
reduceLeft(_ withFallback _)
// Combine all the config together into one big config
val combinedConfig: Config = Seq(
systemPropertyConfig,
directConfig,
applicationConfig,
playOverridesConfig,
referenceConfig
).reduceLeft(_ withFallback _)
// resolve ${foo.bar}
//
val resolvedConfig = combinedConfig.resolve
Configuration(resolvedConfig)
} catch {
case e: ConfigException => throw configError(e.origin, e.getMessage,
}
27
rootDir
Option.get
getOrElse(throw new Exception)
val rootDir: File = {
// play.server.dir
val path = configuration
.getString("play.server.dir")
.getOrElse(throw ServerStartException("No root server path supplied"
val file = new File(path)
if (!(file.exists && file.isDirectory)) {
throw ServerStartException(s"Bad root server path: $path")
}
file
}
28
http/https port
http/https
def parsePort(portType: String): Option[Int] = {
configuration.getString(s"play.server.${portType}.port").flatMap {
case "disabled" => None
case str =>
val i = try Integer.parseInt(str) catch {
case _: NumberFormatException => throw ServerStartException(
}
Some(i)
}
}
val httpPort = parsePort("http")
val httpsPort = parsePort("https")
if (!(httpPort orElse httpsPort).isDefined) throw ServerStartException
29
TypeSafe Con g
5
reduceLeft Combine
{}
Option.get getOrElse(throw new
Exception)
30
2. PID src
// 2. Create a PID file before we do any real work
val pidFile = createPidFile(process, config.configuration)
def createPidFile(process: ServerProcess, configuration: Configuration
// "play.server.pidfile.path"
val pidFilePath = configuration
.getString("play.server.pidfile.path")
.getOrElse(throw ServerStartException("Pid file path
// "play.server.pidfile.path" "/dev/null"
if (pidFilePath == "/dev/null") None else {
val pidFile = new File(pidFilePath).getAbsoluteFile
// PID
if (pidFile.exists) {
throw ServerStartException(s"This application is already running (Or
}
val pid = process.pid getOrElse (throw ServerStartException("Couldn't
val out = new FileOutputStream(pidFile)
try out.write(pid.getBytes) finally out.close()
Some(pidFile)
}
} 31
3. Application src
play.api.Application UT
// 3. Start the application
val application: Application = {
val environment = Environment(config.rootDir,
process.classLoader,
Mode.Prod)
val context = ApplicationLoader.createContext(environment)
val loader = ApplicationLoader(context)
loader.load(context)
}
Play.start(application)
32
play.api.Environment
case class
/**
* The environment for the application.
*
* Captures concerns relating to the classloader and
* the filesystem for the application.
*
* @param
* @param classLoader
* @param mode Prod/Dev/Test 3 )
*/
case class Environment(
rootPath: File,
classLoader: ClassLoader,
mode: Mode.Mode
)
33
ApplicationLoader#createContext
SourceMapper:
WebCommands: Evolutions
/**
* Create an application loading context.
* Locates and loads the necessary configuration files for the application
*/
def createContext(environment: Environment,
initialSettings: Map[String, AnyRef] = Map.empty[String, AnyRef],
sourceMapper: Option[SourceMapper] = None,
webCommands: WebCommands = new DefaultWebCommands) = {
val configuration = Configuration.load(environment, initialSettings)
Context(environment, sourceMapper, webCommands, configuration)
}
34
ApplicationLoader#apply
Scala/Java
// Locate and instantiate the ApplicationLoader.
def apply(context: Context): ApplicationLoader = {
Reflect.configuredClass[
ApplicationLoader, play.ApplicationLoader, GuiceApplicationLoader
](
context.environment,
PlayConfig(context.initialConfiguration),
"play.application.loader",
classOf[GuiceApplicationLoader].getName
) match {
case None => /* */
new GuiceApplicationLoader /* */
case Some(Left(scalaClass)) => /* Scala */
scalaClass.newInstance
case Some(Right(javaClass)) => /* Java */
javaClass.newInstance
}
} 35
ApplicationLoader
ApplicationLoader
Play Runtime DI Compile time DI
play.application.loader ApplicationLoader
Compile time DI
Scala trait Java interface
Guice Runtime DI
36
play.api.inject.guice.GuiceApplicationLoader
Guice
def this()
/**
* An ApplicationLoader that uses Guice to bootstrap the application.
*
* Subclasses can override the `builder` and `overrides` methods.
*/
class GuiceApplicationLoader(
protected val initialBuilder: GuiceApplicationBuilder
) extends ApplicationLoader {
// empty constructor needed for instantiating via reflection
def this() = this(new GuiceApplicationBuilder)
}
37
GuiceApplicationBuilder
Application Guice
final case class GuiceApplicationBuilder(
environment: Environment = Environment.simple(),
configuration: Configuration = Configuration.empty,
modules: Seq[GuiceableModule] = Seq.empty,
overrides: Seq[GuiceableModule] = Seq.empty,
disabled: Seq[Class[_]] = Seq.empty,
binderOptions: Set[BinderOption] = BinderOption.defaults,
eagerly: Boolean = false,
loadConfiguration: Environment => Configuration = Configuration.load,
global: Option[GlobalSettings.Deprecated] = None,
loadModules: (Environment, Configuration) => Seq[GuiceableModule] =
) extends GuiceBuilder[GuiceApplicationBuilder](
environment, configuration, modules, overrides, disabled, binderOptions,
)
38
src
loader GuiceApplicationLoader
loader GuiceApplicationBuilder
loader.load
// Start the application
val application: Application = {
val environment = Environment(config.rootDir, process.classLoader,
val context = ApplicationLoader.createContext(environment)
val loader = ApplicationLoader(context)
//
loader.load(context)
}
39
GuiceApplicationLoader#load
GuiceApplicationBuilder build
builder Con g Environment
override final def load(
context: ApplicationLoader.Context
): Application = {
builder(context).build
}
protected def builder(
context: ApplicationLoader.Context
): GuiceApplicationBuilder = {
initialBuilder.disableCircularProxies()
.in(context.environment)
.loadConfig(context.initialConfiguration)
.overrides(overrides(context): _*)
}
protected def overrides(context: ApplicationLoader.Context): Seq[Guiceable
GuiceApplicationLoader.defaultOverrides(context)
} 40
GuiceApplicationLoader#defaultOverrides
Guice Module
object GuiceApplicationLoader {
/**
* The default overrides provided by the Scala and Java GuiceApplication
*/
def defaultOverrides(
context: ApplicationLoader.Context
): Seq[GuiceableModule] = {
Seq(
bind[OptionalSourceMapper] to new OptionalSourceMapper(context.sourc
bind[WebCommands] to context.webCommands,
bind[DefaultApplicationLifecycle] to context.lifecycle)
}
}
41
GuiceApplicationBuilder#build
injector Application
injector(): play.api.injector.PlayInjector
def injector Guice Injector
override final def load(
context: ApplicationLoader.Context
): Application = {
builder(context).build //
}
/**
* Create a new Play Application using this configured builder.
*/
def build(): Application = injector().instanceOf[Application]
42
GuiceBuilder#injector
GuiceApplicationBuilder GuiceBuilder
Guice Injector
/**
* Create a Play Injector backed by Guice using this configured builder.
*/
def injector(): PlayInjector = {
try {
val stage = /* */
// Injector(com.google.inject.Injector)
val guiceInjector =
Guice.createInjector(stage, applicationModule())
// Injector PlayInjector
guiceInjector.getInstance(classOf[PlayInjector])
} catch {
// ...
}
} 43
GuiceBuilder#applicationModule
PlayInjector GuiceInjector
conf Module
// Create a Play Injector backed by Guice using this configured builder.
def applicationModule(): GuiceModule = createModule()
def createModule(): GuiceModule = {
import scala.collection.JavaConverters._
val injectorModule = GuiceableModule.guice(Seq(
bind[PlayInjector].to[GuiceInjector],
bind[play.inject.Injector].to[play.inject.DelegateInjector]
), binderOptions)
val enabledModules = modules.map(_.disable(disabled))
val bindingModules = GuiceableModule.guiced(environment, configuration
val overrideModules = GuiceableModule.guiced(environment, configuratio
GuiceModules.`override`(bindingModules.asJava).`with`(overrideModules.
}
44
GuiceInjector
GuiceInjector Guice Injector
instanceOf[T]
injector().instanceOf[Application]
class GuiceInjector @Inject() (
injector: com.google.inject.Injector
) extends PlayInjector {
def instanceOf[T](implicit ct: ClassTag[T]) = instanceOf(ct.runtimeClass
def instanceOf[T](clazz: Class[T]) = injector.getInstance(clazz)
def instanceOf[T](key: BindingKey[T]) = injector.getInstance(GuiceKey
}
45
Application
Guice Injector con g
framework/src/play/src/main/resources/reference
.conf
play {
modules {
# The enabled modules that should be automatically loaded.
enabled += "play.api.inject.BuiltinModule" #
enabled += "play.api.i18n.I18nModule"
# A way to disable modules that are automatically enabled
disabled = []
}
}
46
play.api.inject.BuiltinModule
Provider
class BuiltinModule extends Module {
def bindings(env: Environment, configuration: Configuration): Seq[
// ... ...
Seq(
bind[Environment] to env,
bind[Configuration].toProvider[ConfigurationProvider],
bind[DefaultApplicationLifecycle].toSelf,
bind[ApplicationLifecycle].to(bind[DefaultApplicationLifecycle
bind[Application].to[DefaultApplication], //
bind[play.Application].to[play.DefaultApplication],
bind[ActorSystem].toProvider[ActorSystemProvider],
bind[Materializer].toProvider[MaterializerProvider],
bind[ExecutionContext].to[ExecutionContextExecutor],
// ... ...
}
47
DefaultApplication
Inject
@Singleton
class DefaultApplication @Inject() (
environment: Environment,
applicationLifecycle: DefaultApplicationLifecycle,
override val injector: Injector,
override val configuration: Configuration,
override val requestHandler: HttpRequestHandler,
override val errorHandler: HttpErrorHandler,
override val actorSystem: ActorSystem,
override val materializer: Materializer) extends Application {
def path = environment.rootPath
def classloader = environment.classLoader
def mode = environment.mode
def stop() = applicationLifecycle.stop()
} 48
src
// 3. Start the application
val application: Application = {
val environment = Environment(config.rootDir,
process.classLoader,
Mode.Prod)
val context = ApplicationLoader.createContext(environment)
val loader = ApplicationLoader(context)
loader.load(context)
}
//
Play.start(application)
49
play.api.Play#start
@volatile private[play] var _currentApp: Application = _
def start(app: Application) {
stop(_currentApp)
_currentApp = app
Threads.withContextClassLoader(app.classloader) {
app.global.beforeStart(app)
app.routes
app.global.onStart(app)
}
app.mode match {
case Mode.Test =>
// started
case mode => logger.info("Application started (" + mode + ")")
}
}
50
Application
ApplicationLoader Application
ApplicationLoader
Guice
GuiceApplicationLoader
GuiceApplicationBuilder
BuiltinModules
DefaultApplication
51
HTTP
netty src
ServerProvider Server
hook
PID
val serverProvider: ServerProvider =
ServerProvider.fromConfiguration(
process.classLoader, config.configuration
)
val server = serverProvider.createServer(config, application)
process.addShutdownHook {
server.stop()
pidFile.foreach(_.delete())
assert(!pidFile.exists(_.exists), "PID file should not exist!")
}
server
52
ServerProvider#fromCon guration
play.server.provider
new
framework/src/play-netty-
server/src/main/resources/reference.conf
play.core.server.NettyServerProvider
akka-http experimental
def fromConfiguration(classLoader: ClassLoader, configuration: Configurati
val ClassNameConfigKey = "play.server.provider"
val className: String = configuration.getString(ClassNameConfigKey
val clazz = try classLoader.loadClass(className) catch { // }
val ctor = try clazz.getConstructor() catch { // }
ctor.newInstance().asInstanceOf[ServerProvider]
}
53
NettyServerProvider#createServer
play.core.server.NettyServer new
def createServer(context: ServerProvider.Context) =
new NettyServer(
context.config,
context.appProvider,
context.stopHook,
context.actorSystem
)(
context.materializer
)
54
NettyServer
val bind
new src
class NettyServer(/* */) {
// Maybe the HTTP server channel
private val httpChannel =
config.port.map(bindChannel(_, secure = false))
// Maybe the HTTPS server channel
private val httpsChannel =
config.sslPort.map(bindChannel(_, secure = true))
private def bindChannel(port: Int, secure: Boolean): Channel = {
val protocolName = if (secure) "HTTPS" else "HTTP"
val address = new InetSocketAddress(config.address, port)
val (serverChannel, channelSource) = bind(address)
channelSource.runWith(channelSink(port = port, secure = secure))
/* */
}
}
55
NettyServer#bind
netty akka-stream Source
HTTP Source
OK
Source => Sink
private def bind(address: InetSocketAddress): (Channel, Source[Channel
val serverChannelEventLoop = eventLoop.next
// Watches for channel events, and pushes them through a reactive stre
val channelPublisher = new HandlerPublisher(serverChannelEventLoop, cl
/* */
val channel = bootstrap.bind.await().channel()
allChannels.add(channel)
(channel, Source.fromPublisher(channelPublisher))
}
56
NettyServer#channelSink
input(Source) Sink
PlayRequestHandler
val (serverChannel, channelSource) = bind(address)
//
channelSource.runWith(channelSink(port = port, secure = secure))
// :
private def channelSink(port: Int, secure: Boolean): Sink[Channel, Future
Sink.foreach[Channel] { (connChannel: Channel) =>
val pipeline = connChannel.pipeline() /* ... */
pipeline.addLast("decoder", new HttpRequestDecoder(maxInitialLineLengt
val requestHandler = new PlayRequestHandler(this) //
pipeline.addLast("http-handler", new HttpStreamsServerHandler(Seq
pipeline.addLast("request-handler", requestHandler)     
/* ... */
}
} 57
NettyServer
akka-stream netty
(Source/Sink)
play.server.netty.transport native
epoll
(Linux)
PlayRequestHandler (
private lazy val transport = conf.getString("transport") match {
case "native" => Native
case "jdk" => Jdk
}
58
59
ProdServerStart#main
Con guration
ApplicationLoader/GuiceApplicationLoader/Guice
ApplicationBuilder Application
Play.start Application
NettyServerProvider NettyServer
HTTP
PlayRequestHandler
60
Typsafe Con g/Google Guice/JBoss
Netty/Akka/Akka-Stream
sbt run
ProdServer
61
62
63
PlayRequestHandler
ChannelInboundHandlerAdapter netty class
Netty
def channelRead def handle
private[play] class PlayRequestHandler(
val server: NettyServer
) extends ChannelInboundHandlerAdapter {
// ...
override def channelRead(ctx: ChannelHandlerContext, msg: Object):
// Handle the given request.
def handle(
channel: Channel, request: HttpRequest
): Future[HttpResponse] = { /* */ }
} 64
PlayRequestHandler.channelRead
Netty HttpRequest handle
Write
trampoline ExecutionContext
override def channelRead(ctx: ChannelHandlerContext, msg: Object): Unit
logger.trace(s"channelRead: ctx = ${ctx}, msg = ${msg}")
msg match {
case req: HttpRequest =>
requestsInFlight.incrementAndGet()
/* handle */
val future: Future[HttpResponse] = handle(ctx.channel(), req)
import play.api.libs.iteratee.Execution.Implicits.trampoline
lastResponseSent = lastResponseSent.flatMap { /* */
ctx.writeAndFlush(httpResponse) /* Write */
}
}
}
65
PlayRequesthHandler.handle
NettyModelConversion Netty
io.netty.handler.codec.http.HttpRequest Play
play.api.mvc.RequestHeader
Try[RequestHeader]
def handle(
channel: Channel, request: HttpRequest
): Future[HttpResponse] = {
import play.api.libs.iteratee.Execution.Implicits.trampoline
val requestId = RequestIdProvider.requestIDs.incrementAndGet()
//
val tryRequest = modelConversion.convertRequest(
requestId,
channel.remoteAddress().asInstanceOf[InetSocketAddress],
Option(channel.pipeline().get(classOf[SslHandler])),
request
)
} 66
PlayRequestHandler.handle
Success server.getHandlerFor
Right Application handler
Left Result
val (requestHeader, resultOrHandler) = tryRequest match {
case Failure(exception: TooLongFrameException) => clientError(Status
case Failure(exception) => clientError(Status.BAD_REQUEST, exception.g
case Success(untagged) =>
server.getHandlerFor(untagged) match {
case Left(directResult) =>
untagged -> Left(directResult)
case Right((taggedRequestHeader, handler, application)) =>
taggedRequestHeader -> Right((handler, application))
}
}
67
play.core.server.Server#getHandleFor
Handler
Right Handler
Left Result
WebCommand Left Result
DefaultHttpRequestHandler handleForRequest
def getHandlerFor(
request: RequestHeader
): Either[Future[Result], (RequestHeader, Handler, Application)] = {
/* */
application.requestHandler.handlerForRequest(request) match {
case (requestHeader, handler) => Right((requestHeader, handler, applic
}
} 68
DefaultHttpRequestHandler#handleForReque
st
HEAD GET
def handlerForRequest(request: RequestHeader) = {
/* ... */
val (routedRequest, handler) = routeRequest(request) map {
case handler: RequestTaggingHandler =>
(handler.tagRequest(request), handler)
case otherHandler => (request, otherHandler)
} getOrElse {
// We automatically permit HEAD requests against any GETs without the
// add an explicit mapping in Routes
request.method match {
case HttpVerbs.HEAD =>
routeRequest(request.copy(method = HttpVerbs.GET)) match {
/* */
/* */
(routedRequest, filterHandler(rh => handler)(routedRequest))
}
69
routeRequest, Router, RoutesProvider
class DefaultHttpRequestHandler {
def routeRequest(request: RequestHeader): Option[Handler] = {
router.handlerFor(request)
}
}
trait Router {
def handlerFor(request: RequestHeader): Option[Handler] = {
routes.lift(request)
}
}
class RoutesProvider { /* */
lazy val get = {
val prefix = httpConfig.context
val router = Router.load(environment, configuration)
.fold[Router](Router.empty)(injector.instanceOf(_))
router.withPrefix(prefix)
}
}
70
routeRequest
Router BuiltinModule
bind[Router].toProvider[RoutesProvider]
RoutesProvider#get routes-compiler
Routes routes
Gist
71
routes.Routes
conf/routes routes-compiler
target/scala-2.11/routes/main/router/Routes.scala
// Scala
class Routes(
override val errorHandler: play.api.http.HttpErrorHandler,
// @LINE:6
HomeController_0: controllers.HomeController,
// @LINE:8
CountController_3: controllers.CountController,
// @LINE:10
AsyncController_2: controllers.AsyncController,
// @LINE:13
Assets_1: controllers.Assets,
val prefix: String
) extends GeneratedRouter
72
Rourtes.routes
RequestHeader Handler
PartialFunction
def routes: PartialFunction[RequestHeader, Handler] = {
// @LINE:6
case controllers_HomeController_index0_route(params) =>
call {
controllers_HomeController_index0_invoker.call(
HomeController_0.index
)
}
// @LINE:8
case controllers_CountController_count1_route(params) =>
call {
controllers_CountController_count1_invoker.call(
CountController_3.count
)
}
/* */
} 73
Handler src
val (requestHeader, resultOrHandler) = /* */
resultOrHandler match {
//execute normal action
case Right((action: EssentialAction, app)) =>
val recovered = EssentialAction { rh =>
import play.api.libs.iteratee.Execution.Implicits.trampoline
action(rh).recoverWith {
case error => app.errorHandler.onServerError(rh, error)
}
}
handleAction(recovered, requestHeader, request, Some(app))
/* */
}
EssentialAction
EssentialAction { rh => action(rh)
74
EssentialAction
app/controllers/HomeController.scala
package controllers
import javax.inject.{ Inject, Singleton }
import play.api.mvc.{ Controller, Action, AnyContent }
@Singleton
class HomeController @Inject() extends Controller {
def index: Action[AnyContent] = Action { req =>
Ok(views.html.index("Your new application is ready."))
}
}
conf/routes
GET / controllers.HomeController.index
GET /count controllers.CountController.count
GET /message controllers.AsyncController.message
75
Controller Action
def index: Action[AnyContent] = Action { req =>
Ok(views.html.index("Your new application is ready."))
}
Action { req => object Action apply
trait Action[A]
A Action
Action[JsValue] JSON
req Request[A] A
Request Result
76
Action BodyParser
Action[A] BodyParser[A]
BodyParser[A] A
RequestHeader -> RequestBody(Array[Byte]) ->
Result
RequestBody Asynchornous Stream
InputStream Akka-
stream
77
Accumulator[ByteString, Result]
Action RequestHeader => Body => Result
Accumulator
RequestHeader => Accumulator[ByteString,
Result]
Accumulator Akka-stream(Source)
ByteString Array[Byte] (
Akka )
Async
Async FW
78
Action[A]
Action[A] Result
RequestHeader => Accumulator[ByteString, Result]
Play
What is EssentialAction
What is BodyParser
79
EssentialAction
EssentialAction Handler MixIn
Action EssentialAction
EssentialAction
RequestHeader => Accumulator[ByteString, Result]
trait EssentialAction
extends (RequestHeader => Accumulator[ByteString, Result])
with Handler { self =>
def apply() = this
}
trait Action[A] extends EssentialAction
80
: Function
Function
trait Function1[-T1, +R]
RequestHeader => Accumulator[ByteString, Result]
Funtion1[RequestHeader, Accumulator[ByteString,
Result]]
// Intellij -T1 => R
trait EssentialAction
extends Function1[RequestHeader, Accumulator[ByteString, Result]]
81
Action#apply
BodyParser
def apply(request: Request[A]): Future[Result] = {
/* */
}
//
def apply(rh: RequestHeader): Accumulator[ByteString, Result] =
parser(rh).mapFuture { // parser BodyParser
case Left(r) => /* ... (T_T) */
case Right(a) => /* */
val request = Request(rh, a)
apply(request) // apply
}(executionContext)
82
PlayRequestHandler
resultOrHandler match {
//execute normal action
case Right((action: EssentialAction, app)) =>
val recovered = EssentialAction { rh =>
import play.api.libs.iteratee.Execution.Implicits.trampoline
// action(rh) Accumulator
action(rh).recoverWith {
case error => app.errorHandler.onServerError(rh, error)
}
}
//
handleAction(recovered, requestHeader, request, Some(app))
/* */
}
83
handleAction
Action
private def handleAction(action: EssentialAction, requestHeader: RequestHe
request: HttpRequest, app: Option[Application]): Future[HttpResponse
for {
bodyParser <- Future(action(requestHeader))(mat.executionContext)
actionResult <- {
val body = modelConversion.convertRequestBody(request)
(body match {
case None => bodyParser.run()
case Some(source) => bodyParser.run(source)
}).recoverWith { /* ... */ }
}
validatedResult <- { /* Clean and validate the action's result */
convertedResult <- { /* Netty HttpResponse */
modelConversion.convertResult(validatedResult, requestHeader, reques
}
} yield convertedResult
}
84
handleAction
bodyParser Action apply
Accumulator[ByteString, Result]
body Netty
Accumulator run
actionResult Result
Ok
Result Netty HttpResponse
85
src
HttpResponse writeAndFlush
override def channelRead(ctx: ChannelHandlerContext, msg: Object): Unit
msg match {
case req: HttpRequest =>
requestsInFlight.incrementAndGet()
val future: Future[HttpResponse] = handle(ctx.channel(), req)
/* handle */
/* */
import play.api.libs.iteratee.Execution.Implicits.trampoline
lastResponseSent = lastResponseSent.flatMap { /* */
ctx.writeAndFlush(httpResponse)
}
}
}
86
87
88

More Related Content

What's hot

KeycloakでFAPIに対応した高セキュリティなAPIを公開する
KeycloakでFAPIに対応した高セキュリティなAPIを公開するKeycloakでFAPIに対応した高セキュリティなAPIを公開する
KeycloakでFAPIに対応した高セキュリティなAPIを公開するHitachi, Ltd. OSS Solution Center.
 
サーバーサイド Kotlin のテストフレームワーク事情
サーバーサイド Kotlin のテストフレームワーク事情サーバーサイド Kotlin のテストフレームワーク事情
サーバーサイド Kotlin のテストフレームワーク事情Shinya Mochida
 
Hexagonal architecture vs Functional core / Imperative shell
Hexagonal architecture vs Functional core / Imperative shellHexagonal architecture vs Functional core / Imperative shell
Hexagonal architecture vs Functional core / Imperative shellThomas Pierrain
 
Guaranteeing Memory Safety in Rust
Guaranteeing Memory Safety in RustGuaranteeing Memory Safety in Rust
Guaranteeing Memory Safety in Rustnikomatsakis
 
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Scott Wlaschin
 
What's new in Spring Batch 5
What's new in Spring Batch 5What's new in Spring Batch 5
What's new in Spring Batch 5ikeyat
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Scott Wlaschin
 
Scaling up task processing with Celery
Scaling up task processing with CeleryScaling up task processing with Celery
Scaling up task processing with CeleryNicolas Grasset
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション土岐 孝平
 
XXE、SSRF、安全でないデシリアライゼーション入門
XXE、SSRF、安全でないデシリアライゼーション入門XXE、SSRF、安全でないデシリアライゼーション入門
XXE、SSRF、安全でないデシリアライゼーション入門Hiroshi Tokumaru
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...Philip Schwarz
 
Linux Binary Exploitation - Heap Exploitation
Linux Binary Exploitation - Heap Exploitation Linux Binary Exploitation - Heap Exploitation
Linux Binary Exploitation - Heap Exploitation Angel Boy
 
Djangoフレームワークのユーザーモデルと認証
Djangoフレームワークのユーザーモデルと認証Djangoフレームワークのユーザーモデルと認証
Djangoフレームワークのユーザーモデルと認証Shinya Okano
 
以 Laravel 經驗開發 Hyperf 應用
以 Laravel 經驗開發 Hyperf 應用以 Laravel 經驗開發 Hyperf 應用
以 Laravel 經驗開發 Hyperf 應用Shengyou Fan
 
Go初心者がGoでコマンドラインツールの作成に挑戦した話
Go初心者がGoでコマンドラインツールの作成に挑戦した話Go初心者がGoでコマンドラインツールの作成に挑戦した話
Go初心者がGoでコマンドラインツールの作成に挑戦した話dcubeio
 
「DNS浸透いうな」と言うけれど… (#ssmjp 2018/07)
「DNS浸透いうな」と言うけれど… (#ssmjp 2018/07)「DNS浸透いうな」と言うけれど… (#ssmjp 2018/07)
「DNS浸透いうな」と言うけれど… (#ssmjp 2018/07)Yoshikazu GOTO
 
A topology of memory leaks on the JVM
A topology of memory leaks on the JVMA topology of memory leaks on the JVM
A topology of memory leaks on the JVMRafael Winterhalter
 

What's hot (20)

KeycloakでFAPIに対応した高セキュリティなAPIを公開する
KeycloakでFAPIに対応した高セキュリティなAPIを公開するKeycloakでFAPIに対応した高セキュリティなAPIを公開する
KeycloakでFAPIに対応した高セキュリティなAPIを公開する
 
サーバーサイド Kotlin のテストフレームワーク事情
サーバーサイド Kotlin のテストフレームワーク事情サーバーサイド Kotlin のテストフレームワーク事情
サーバーサイド Kotlin のテストフレームワーク事情
 
Hexagonal architecture vs Functional core / Imperative shell
Hexagonal architecture vs Functional core / Imperative shellHexagonal architecture vs Functional core / Imperative shell
Hexagonal architecture vs Functional core / Imperative shell
 
Guaranteeing Memory Safety in Rust
Guaranteeing Memory Safety in RustGuaranteeing Memory Safety in Rust
Guaranteeing Memory Safety in Rust
 
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
 
What's new in Spring Batch 5
What's new in Spring Batch 5What's new in Spring Batch 5
What's new in Spring Batch 5
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)
 
Dapper performance
Dapper performanceDapper performance
Dapper performance
 
Scaling up task processing with Celery
Scaling up task processing with CeleryScaling up task processing with Celery
Scaling up task processing with Celery
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
 
XXE、SSRF、安全でないデシリアライゼーション入門
XXE、SSRF、安全でないデシリアライゼーション入門XXE、SSRF、安全でないデシリアライゼーション入門
XXE、SSRF、安全でないデシリアライゼーション入門
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
 
Linux Binary Exploitation - Heap Exploitation
Linux Binary Exploitation - Heap Exploitation Linux Binary Exploitation - Heap Exploitation
Linux Binary Exploitation - Heap Exploitation
 
Djangoフレームワークのユーザーモデルと認証
Djangoフレームワークのユーザーモデルと認証Djangoフレームワークのユーザーモデルと認証
Djangoフレームワークのユーザーモデルと認証
 
Android binder-ipc
Android binder-ipcAndroid binder-ipc
Android binder-ipc
 
以 Laravel 經驗開發 Hyperf 應用
以 Laravel 經驗開發 Hyperf 應用以 Laravel 經驗開發 Hyperf 應用
以 Laravel 經驗開發 Hyperf 應用
 
Go初心者がGoでコマンドラインツールの作成に挑戦した話
Go初心者がGoでコマンドラインツールの作成に挑戦した話Go初心者がGoでコマンドラインツールの作成に挑戦した話
Go初心者がGoでコマンドラインツールの作成に挑戦した話
 
KeycloakでAPI認可に入門する
KeycloakでAPI認可に入門するKeycloakでAPI認可に入門する
KeycloakでAPI認可に入門する
 
「DNS浸透いうな」と言うけれど… (#ssmjp 2018/07)
「DNS浸透いうな」と言うけれど… (#ssmjp 2018/07)「DNS浸透いうな」と言うけれど… (#ssmjp 2018/07)
「DNS浸透いうな」と言うけれど… (#ssmjp 2018/07)
 
A topology of memory leaks on the JVM
A topology of memory leaks on the JVMA topology of memory leaks on the JVM
A topology of memory leaks on the JVM
 

Viewers also liked

並行実行制御の最適化手法
並行実行制御の最適化手法並行実行制御の最適化手法
並行実行制御の最適化手法Sho Nakazono
 
ハイブリッド言語Scalaを使う
ハイブリッド言語Scalaを使うハイブリッド言語Scalaを使う
ハイブリッド言語Scalaを使うbpstudy
 
Functional and Algebraic Domain Modeling
Functional and Algebraic Domain ModelingFunctional and Algebraic Domain Modeling
Functional and Algebraic Domain ModelingDebasish Ghosh
 
やさしいIteratee入門
やさしいIteratee入門やさしいIteratee入門
やさしいIteratee入門Takashi Kawachi
 
PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション
PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC WebアプリケーションPlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション
PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC WebアプリケーションKazuhiro Hara
 
とにかく対立したい子ども達へのクラウドを使った対処法
とにかく対立したい子ども達へのクラウドを使った対処法とにかく対立したい子ども達へのクラウドを使った対処法
とにかく対立したい子ども達へのクラウドを使った対処法広告制作会社
 
Scala Refactoring for Fun and Profit (Japanese subtitles)
Scala Refactoring for Fun and Profit (Japanese subtitles)Scala Refactoring for Fun and Profit (Japanese subtitles)
Scala Refactoring for Fun and Profit (Japanese subtitles)Tomer Gabel
 
Functional Programming For All - Scala Matsuri 2016
Functional Programming For All - Scala Matsuri 2016Functional Programming For All - Scala Matsuri 2016
Functional Programming For All - Scala Matsuri 2016Zachary Abbott
 
Contributing to Scala OSS from East Asia #ScalaMatsuri
 Contributing to Scala OSS from East Asia #ScalaMatsuri Contributing to Scala OSS from East Asia #ScalaMatsuri
Contributing to Scala OSS from East Asia #ScalaMatsuriKazuhiro Sera
 
Rubyからscalaに変えるべき15の理由
Rubyからscalaに変えるべき15の理由Rubyからscalaに変えるべき15の理由
Rubyからscalaに変えるべき15の理由Yukishige Nakajo
 
The Play Framework at LinkedIn
The Play Framework at LinkedInThe Play Framework at LinkedIn
The Play Framework at LinkedInYevgeniy Brikman
 
あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)x1 ichi
 
Javaアプリケーションサーバ 構築・運用の勘所
Javaアプリケーションサーバ 構築・運用の勘所Javaアプリケーションサーバ 構築・運用の勘所
Javaアプリケーションサーバ 構築・運用の勘所Takahiro YAMADA
 
Pythonによるwebアプリケーション入門 - Django編-
Pythonによるwebアプリケーション入門 - Django編- Pythonによるwebアプリケーション入門 - Django編-
Pythonによるwebアプリケーション入門 - Django編- Hironori Sekine
 
1.1.7 Система огнестойких проходок Vulcan
1.1.7 Система огнестойких проходок Vulcan1.1.7 Система огнестойких проходок Vulcan
1.1.7 Система огнестойких проходок VulcanIgor Golovin
 

Viewers also liked (20)

並行実行制御の最適化手法
並行実行制御の最適化手法並行実行制御の最適化手法
並行実行制御の最適化手法
 
ハイブリッド言語Scalaを使う
ハイブリッド言語Scalaを使うハイブリッド言語Scalaを使う
ハイブリッド言語Scalaを使う
 
アクセシブルなモーダルダイアログの作り方 #scripty05
アクセシブルなモーダルダイアログの作り方 #scripty05アクセシブルなモーダルダイアログの作り方 #scripty05
アクセシブルなモーダルダイアログの作り方 #scripty05
 
Functional and Algebraic Domain Modeling
Functional and Algebraic Domain ModelingFunctional and Algebraic Domain Modeling
Functional and Algebraic Domain Modeling
 
やさしいIteratee入門
やさしいIteratee入門やさしいIteratee入門
やさしいIteratee入門
 
PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション
PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC WebアプリケーションPlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション
PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション
 
とにかく対立したい子ども達へのクラウドを使った対処法
とにかく対立したい子ども達へのクラウドを使った対処法とにかく対立したい子ども達へのクラウドを使った対処法
とにかく対立したい子ども達へのクラウドを使った対処法
 
akka-streamのマイクロサービスへの適用
akka-streamのマイクロサービスへの適用akka-streamのマイクロサービスへの適用
akka-streamのマイクロサービスへの適用
 
ScalaMatsuri 2016
ScalaMatsuri 2016ScalaMatsuri 2016
ScalaMatsuri 2016
 
Scala profiling
Scala profilingScala profiling
Scala profiling
 
Scala Refactoring for Fun and Profit (Japanese subtitles)
Scala Refactoring for Fun and Profit (Japanese subtitles)Scala Refactoring for Fun and Profit (Japanese subtitles)
Scala Refactoring for Fun and Profit (Japanese subtitles)
 
Functional Programming For All - Scala Matsuri 2016
Functional Programming For All - Scala Matsuri 2016Functional Programming For All - Scala Matsuri 2016
Functional Programming For All - Scala Matsuri 2016
 
Contributing to Scala OSS from East Asia #ScalaMatsuri
 Contributing to Scala OSS from East Asia #ScalaMatsuri Contributing to Scala OSS from East Asia #ScalaMatsuri
Contributing to Scala OSS from East Asia #ScalaMatsuri
 
Rubyからscalaに変えるべき15の理由
Rubyからscalaに変えるべき15の理由Rubyからscalaに変えるべき15の理由
Rubyからscalaに変えるべき15の理由
 
Go Workshop Day 1
Go Workshop Day 1Go Workshop Day 1
Go Workshop Day 1
 
The Play Framework at LinkedIn
The Play Framework at LinkedInThe Play Framework at LinkedIn
The Play Framework at LinkedIn
 
あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)
 
Javaアプリケーションサーバ 構築・運用の勘所
Javaアプリケーションサーバ 構築・運用の勘所Javaアプリケーションサーバ 構築・運用の勘所
Javaアプリケーションサーバ 構築・運用の勘所
 
Pythonによるwebアプリケーション入門 - Django編-
Pythonによるwebアプリケーション入門 - Django編- Pythonによるwebアプリケーション入門 - Django編-
Pythonによるwebアプリケーション入門 - Django編-
 
1.1.7 Система огнестойких проходок Vulcan
1.1.7 Система огнестойких проходок Vulcan1.1.7 Система огнестойких проходок Vulcan
1.1.7 Система огнестойких проходок Vulcan
 

Similar to こわくないよ❤️ Playframeworkソースコードリーディング入門

Go Web Development
Go Web DevelopmentGo Web Development
Go Web DevelopmentCheng-Yi Yu
 
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+ConFoo
 
TDC2018SP | Trilha Go - Processando analise genetica em background com Go
TDC2018SP | Trilha Go - Processando analise genetica em background com GoTDC2018SP | Trilha Go - Processando analise genetica em background com Go
TDC2018SP | Trilha Go - Processando analise genetica em background com Gotdc-globalcode
 
Taking Jenkins Pipeline to the Extreme
Taking Jenkins Pipeline to the ExtremeTaking Jenkins Pipeline to the Extreme
Taking Jenkins Pipeline to the Extremeyinonavraham
 
FP - Découverte de Play Framework Scala
FP - Découverte de Play Framework ScalaFP - Découverte de Play Framework Scala
FP - Découverte de Play Framework ScalaKévin Margueritte
 
OSCON 2014 - API Ecosystem with Scala, Scalatra, and Swagger at Netflix
OSCON 2014 - API Ecosystem with Scala, Scalatra, and Swagger at NetflixOSCON 2014 - API Ecosystem with Scala, Scalatra, and Swagger at Netflix
OSCON 2014 - API Ecosystem with Scala, Scalatra, and Swagger at NetflixManish Pandit
 
WebTalk - Implementing Web Services with a dedicated Java daemon
WebTalk - Implementing Web Services with a dedicated Java daemonWebTalk - Implementing Web Services with a dedicated Java daemon
WebTalk - Implementing Web Services with a dedicated Java daemonGeert Van Pamel
 
Rntb20200805
Rntb20200805Rntb20200805
Rntb20200805t k
 
Akka Cluster in Java - JCConf 2015
Akka Cluster in Java - JCConf 2015Akka Cluster in Java - JCConf 2015
Akka Cluster in Java - JCConf 2015Jiayun Zhou
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Tsuyoshi Yamamoto
 
Dev ninja -> vagrant + virtualbox + chef-solo + git + ec2
Dev ninja  -> vagrant + virtualbox + chef-solo + git + ec2Dev ninja  -> vagrant + virtualbox + chef-solo + git + ec2
Dev ninja -> vagrant + virtualbox + chef-solo + git + ec2Yros
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch
 
Binary Studio Academy: Concurrency in C# 5.0
Binary Studio Academy: Concurrency in C# 5.0Binary Studio Academy: Concurrency in C# 5.0
Binary Studio Academy: Concurrency in C# 5.0Binary Studio
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleThierry Wasylczenko
 
Railsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshareRailsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slidesharetomcopeland
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applicationsTom Croucher
 
Debugging & profiling node.js
Debugging & profiling node.jsDebugging & profiling node.js
Debugging & profiling node.jstomasperezv
 
Threads, Queues, and More: Async Programming in iOS
Threads, Queues, and More: Async Programming in iOSThreads, Queues, and More: Async Programming in iOS
Threads, Queues, and More: Async Programming in iOSTechWell
 

Similar to こわくないよ❤️ Playframeworkソースコードリーディング入門 (20)

Go Web Development
Go Web DevelopmentGo Web Development
Go Web Development
 
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
 
TDC2018SP | Trilha Go - Processando analise genetica em background com Go
TDC2018SP | Trilha Go - Processando analise genetica em background com GoTDC2018SP | Trilha Go - Processando analise genetica em background com Go
TDC2018SP | Trilha Go - Processando analise genetica em background com Go
 
Taking Jenkins Pipeline to the Extreme
Taking Jenkins Pipeline to the ExtremeTaking Jenkins Pipeline to the Extreme
Taking Jenkins Pipeline to the Extreme
 
FP - Découverte de Play Framework Scala
FP - Découverte de Play Framework ScalaFP - Découverte de Play Framework Scala
FP - Découverte de Play Framework Scala
 
OSCON 2014 - API Ecosystem with Scala, Scalatra, and Swagger at Netflix
OSCON 2014 - API Ecosystem with Scala, Scalatra, and Swagger at NetflixOSCON 2014 - API Ecosystem with Scala, Scalatra, and Swagger at Netflix
OSCON 2014 - API Ecosystem with Scala, Scalatra, and Swagger at Netflix
 
WebTalk - Implementing Web Services with a dedicated Java daemon
WebTalk - Implementing Web Services with a dedicated Java daemonWebTalk - Implementing Web Services with a dedicated Java daemon
WebTalk - Implementing Web Services with a dedicated Java daemon
 
Node intro
Node introNode intro
Node intro
 
Rntb20200805
Rntb20200805Rntb20200805
Rntb20200805
 
Akka Cluster in Java - JCConf 2015
Akka Cluster in Java - JCConf 2015Akka Cluster in Java - JCConf 2015
Akka Cluster in Java - JCConf 2015
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
 
Play!ng with scala
Play!ng with scalaPlay!ng with scala
Play!ng with scala
 
Dev ninja -> vagrant + virtualbox + chef-solo + git + ec2
Dev ninja  -> vagrant + virtualbox + chef-solo + git + ec2Dev ninja  -> vagrant + virtualbox + chef-solo + git + ec2
Dev ninja -> vagrant + virtualbox + chef-solo + git + ec2
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.js
 
Binary Studio Academy: Concurrency in C# 5.0
Binary Studio Academy: Concurrency in C# 5.0Binary Studio Academy: Concurrency in C# 5.0
Binary Studio Academy: Concurrency in C# 5.0
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradle
 
Railsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshareRailsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshare
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Debugging & profiling node.js
Debugging & profiling node.jsDebugging & profiling node.js
Debugging & profiling node.js
 
Threads, Queues, and More: Async Programming in iOS
Threads, Queues, and More: Async Programming in iOSThreads, Queues, and More: Async Programming in iOS
Threads, Queues, and More: Async Programming in iOS
 

Recently uploaded

Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 

Recently uploaded (20)

Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 

こわくないよ❤️ Playframeworkソースコードリーディング入門

  • 3. 3
  • 6. 6
  • 7. 7
  • 9. framework/src build-link play-functional play-netty-utils fork-run play-integration-test play-server fork-run-protocol play-java play-specs2 iteratees play-java-jdbc play-streams play play-java-jpa play-test play-akka-http-server play-java-ws play-ws play-cache play-jdbc routes-compiler play-datacommons play-jdbc-api run-support play-docs play-jdbc-evolutions sbt-fork-run-plugin play-docs-sbt-plugin play-json sbt-plugin play-exceptions play-logback play-filters-helpers play-netty-server 9
  • 10. 10
  • 11. 1. 2. Action Controller 3. Json 4. Applicative 11
  • 12. 12
  • 14. main ag 'def main(' src 3 fork-run sbt src/fork-run/src/main/scala/play/forkrun/ForkRun.scala 28: def main(args: Array[String]): Unit = { src/play-netty-server/src/main/scala/play/core/server/NettyServer.scala 298: def main(args: Array[String]) { src/play-server/src/main/scala/play/core/server/ProdServerStart.scala 20: def main(args: Array[String]) { 14
  • 15. NettyServer def main(args: Array[String]) { System.err.println( s"NettyServer.main is deprecated. Please start your Play server with the ${ProdServerStart.getClass.getName}.main." ) ProdServerStart.main(args) } ProdServerStart 15
  • 16. main grep play-scala sbt dist ProdServerStart declare -a app_mainclass=("play.core.server.ProdServerStart") # java -jar play.core.server.ProdServerStart 16
  • 17. framework/src/play- server/src/main/scala/play/core/server/ProdServe rStart.scala 2 object ProdServerStart { /** * Start a prod mode server from the command line. */ def main(args: Array[String]) { val process = new RealServerProcess(args) start(process) } // ... } 17
  • 18. RealServerProcess ServerProcess JVM /** * Abstracts a JVM process so it can be mocked for testing or to * isolate pseudo-processes within a VM. Code using this class * should use the methods in this class instead of methods like * `System.getProperties()`, `System.exit()`, etc. */ trait ServerProcess class RealServerProcess( val args: Seq[String] ) extends ServerProcess 18
  • 19. ServerProcess trait ServerProcess { /** The ClassLoader that should be used */ def classLoader: ClassLoader /** The command line arguments the process as invoked with */ def args: Seq[String] /** The process's system properties */ def properties: Properties /** Helper for getting properties */ final def prop(name: String): Option[String] = Option(properties.getProp /** The process's id */ def pid: Option[String] /** Add a hook to run when the process shuts down */ def addShutdownHook(hook: => Unit): Unit /** Exit the process with a message and optional cause and return code * def exit(message: String, cause: Option[Throwable] = None, returnCode: } 19
  • 20. RealServerProcess pid class RealServerProcess(val args: Seq[String]) extends ServerProcess def classLoader: ClassLoader = Thread.currentThread.getContextClassLoader def properties: Properties = System.getProperties def pid: Option[String] = ManagementFactory.getRuntimeMXBean .getName.split('@').headOption def addShutdownHook(hook: => Unit): Unit = { Runtime.getRuntime.addShutdownHook(new Thread { override def run() = hook }) } def exit(message: String, cause: Option[Throwable] = None, returnCode: /* ... */ } } 20
  • 21. ProdServerStart#start def main(args: Array[String]): Unit = { val process = new RealServerProcess(args) // start(process) } // 4 def start(process: ServerProcess): ServerWithStop = { try { // 1. Read settings val config: ServerConfig = readServerConfigSettings(process) // 2. Create a PID file before we do any real work val pidFile = createPidFile(process, config.configuration) // 3. Start the application val application: Application = { /* */ } Play.start(application) // 4. Start the server val serverProvider: ServerProvider = ServerProvider.fromConfiguration( val server = serverProvider.createServer(config, application) // ... } 21
  • 22. ProdServerStart#start 1. 2. PID(Process ID) 3. play.api.Application 4. HTTP 22
  • 23. 1. src !(option).isDefined (option).isEmpty def readServerConfigSettings(process: ServerProcess): ServerConfig = { val configuration: Configuration = { /* */ } val rootDir: File = { /* */ } def parsePort(portType: String): Option[Int] = { // configuration http/https parse } val httpPort = parsePort("http") val httpsPort = parsePort("https") if (!(httpPort orElse httpsPort).isDefined) throw ServerStartException val address = configuration.getString("play.server.http.address") .getOrElse("0.0.0.0") ServerConfig(/* */) } 23
  • 24. {} rootDirArg val configuration: Configuration = { // rootDir Some(java.io.File) val rootDirArg: Option[File] = process.args.headOption.map(new File(_)) // Map.empty // play.server.dir // "play.server.dir" -> "${dir.getAbsolutePath}" Map val rootDirConfig = rootDirArg.fold(Map.empty[String, String]) (dir => ServerConfig.rootDirConfig(dir)) // Configuration . Configuration.load( process.classLoader, process.properties, rootDirConfig, true ) } 24
  • 25. play.api.Con guration object Configuration { private[play] def load( classLoader: ClassLoader, properties: Properties, directSettings: Map[String, AnyRef], allowMissingApplicationConf: Boolean): Configuration = { try { // 1. SystemProperty val systemPropertyConfig = /* */ // 2. Map[String, String] val directConfig: Config = ConfigFactory.parseMap(directSettings.asJ // 3. conf/application.conf val applicationConfig: Config = /* */ // 4. play overrides conf val playOverridesConfig: Config = ConfigFactory.parseResources(class // 5. reference.conf val referenceConfig: Config = ConfigFactory.parseResources(classLoad // ... 25
  • 26. 5 1. SystemProperty (System.getProperty) 2. DirectCon g: 3. conf/application.conf ) 4. play overrides con g Akka Play 5. reference.conf Play 26
  • 27. Combine reduceLeft(_ withFallback _) // Combine all the config together into one big config val combinedConfig: Config = Seq( systemPropertyConfig, directConfig, applicationConfig, playOverridesConfig, referenceConfig ).reduceLeft(_ withFallback _) // resolve ${foo.bar} // val resolvedConfig = combinedConfig.resolve Configuration(resolvedConfig) } catch { case e: ConfigException => throw configError(e.origin, e.getMessage, } 27
  • 28. rootDir Option.get getOrElse(throw new Exception) val rootDir: File = { // play.server.dir val path = configuration .getString("play.server.dir") .getOrElse(throw ServerStartException("No root server path supplied" val file = new File(path) if (!(file.exists && file.isDirectory)) { throw ServerStartException(s"Bad root server path: $path") } file } 28
  • 29. http/https port http/https def parsePort(portType: String): Option[Int] = { configuration.getString(s"play.server.${portType}.port").flatMap { case "disabled" => None case str => val i = try Integer.parseInt(str) catch { case _: NumberFormatException => throw ServerStartException( } Some(i) } } val httpPort = parsePort("http") val httpsPort = parsePort("https") if (!(httpPort orElse httpsPort).isDefined) throw ServerStartException 29
  • 30. TypeSafe Con g 5 reduceLeft Combine {} Option.get getOrElse(throw new Exception) 30
  • 31. 2. PID src // 2. Create a PID file before we do any real work val pidFile = createPidFile(process, config.configuration) def createPidFile(process: ServerProcess, configuration: Configuration // "play.server.pidfile.path" val pidFilePath = configuration .getString("play.server.pidfile.path") .getOrElse(throw ServerStartException("Pid file path // "play.server.pidfile.path" "/dev/null" if (pidFilePath == "/dev/null") None else { val pidFile = new File(pidFilePath).getAbsoluteFile // PID if (pidFile.exists) { throw ServerStartException(s"This application is already running (Or } val pid = process.pid getOrElse (throw ServerStartException("Couldn't val out = new FileOutputStream(pidFile) try out.write(pid.getBytes) finally out.close() Some(pidFile) } } 31
  • 32. 3. Application src play.api.Application UT // 3. Start the application val application: Application = { val environment = Environment(config.rootDir, process.classLoader, Mode.Prod) val context = ApplicationLoader.createContext(environment) val loader = ApplicationLoader(context) loader.load(context) } Play.start(application) 32
  • 33. play.api.Environment case class /** * The environment for the application. * * Captures concerns relating to the classloader and * the filesystem for the application. * * @param * @param classLoader * @param mode Prod/Dev/Test 3 ) */ case class Environment( rootPath: File, classLoader: ClassLoader, mode: Mode.Mode ) 33
  • 34. ApplicationLoader#createContext SourceMapper: WebCommands: Evolutions /** * Create an application loading context. * Locates and loads the necessary configuration files for the application */ def createContext(environment: Environment, initialSettings: Map[String, AnyRef] = Map.empty[String, AnyRef], sourceMapper: Option[SourceMapper] = None, webCommands: WebCommands = new DefaultWebCommands) = { val configuration = Configuration.load(environment, initialSettings) Context(environment, sourceMapper, webCommands, configuration) } 34
  • 35. ApplicationLoader#apply Scala/Java // Locate and instantiate the ApplicationLoader. def apply(context: Context): ApplicationLoader = { Reflect.configuredClass[ ApplicationLoader, play.ApplicationLoader, GuiceApplicationLoader ]( context.environment, PlayConfig(context.initialConfiguration), "play.application.loader", classOf[GuiceApplicationLoader].getName ) match { case None => /* */ new GuiceApplicationLoader /* */ case Some(Left(scalaClass)) => /* Scala */ scalaClass.newInstance case Some(Right(javaClass)) => /* Java */ javaClass.newInstance } } 35
  • 36. ApplicationLoader ApplicationLoader Play Runtime DI Compile time DI play.application.loader ApplicationLoader Compile time DI Scala trait Java interface Guice Runtime DI 36
  • 37. play.api.inject.guice.GuiceApplicationLoader Guice def this() /** * An ApplicationLoader that uses Guice to bootstrap the application. * * Subclasses can override the `builder` and `overrides` methods. */ class GuiceApplicationLoader( protected val initialBuilder: GuiceApplicationBuilder ) extends ApplicationLoader { // empty constructor needed for instantiating via reflection def this() = this(new GuiceApplicationBuilder) } 37
  • 38. GuiceApplicationBuilder Application Guice final case class GuiceApplicationBuilder( environment: Environment = Environment.simple(), configuration: Configuration = Configuration.empty, modules: Seq[GuiceableModule] = Seq.empty, overrides: Seq[GuiceableModule] = Seq.empty, disabled: Seq[Class[_]] = Seq.empty, binderOptions: Set[BinderOption] = BinderOption.defaults, eagerly: Boolean = false, loadConfiguration: Environment => Configuration = Configuration.load, global: Option[GlobalSettings.Deprecated] = None, loadModules: (Environment, Configuration) => Seq[GuiceableModule] = ) extends GuiceBuilder[GuiceApplicationBuilder]( environment, configuration, modules, overrides, disabled, binderOptions, ) 38
  • 39. src loader GuiceApplicationLoader loader GuiceApplicationBuilder loader.load // Start the application val application: Application = { val environment = Environment(config.rootDir, process.classLoader, val context = ApplicationLoader.createContext(environment) val loader = ApplicationLoader(context) // loader.load(context) } 39
  • 40. GuiceApplicationLoader#load GuiceApplicationBuilder build builder Con g Environment override final def load( context: ApplicationLoader.Context ): Application = { builder(context).build } protected def builder( context: ApplicationLoader.Context ): GuiceApplicationBuilder = { initialBuilder.disableCircularProxies() .in(context.environment) .loadConfig(context.initialConfiguration) .overrides(overrides(context): _*) } protected def overrides(context: ApplicationLoader.Context): Seq[Guiceable GuiceApplicationLoader.defaultOverrides(context) } 40
  • 41. GuiceApplicationLoader#defaultOverrides Guice Module object GuiceApplicationLoader { /** * The default overrides provided by the Scala and Java GuiceApplication */ def defaultOverrides( context: ApplicationLoader.Context ): Seq[GuiceableModule] = { Seq( bind[OptionalSourceMapper] to new OptionalSourceMapper(context.sourc bind[WebCommands] to context.webCommands, bind[DefaultApplicationLifecycle] to context.lifecycle) } } 41
  • 42. GuiceApplicationBuilder#build injector Application injector(): play.api.injector.PlayInjector def injector Guice Injector override final def load( context: ApplicationLoader.Context ): Application = { builder(context).build // } /** * Create a new Play Application using this configured builder. */ def build(): Application = injector().instanceOf[Application] 42
  • 43. GuiceBuilder#injector GuiceApplicationBuilder GuiceBuilder Guice Injector /** * Create a Play Injector backed by Guice using this configured builder. */ def injector(): PlayInjector = { try { val stage = /* */ // Injector(com.google.inject.Injector) val guiceInjector = Guice.createInjector(stage, applicationModule()) // Injector PlayInjector guiceInjector.getInstance(classOf[PlayInjector]) } catch { // ... } } 43
  • 44. GuiceBuilder#applicationModule PlayInjector GuiceInjector conf Module // Create a Play Injector backed by Guice using this configured builder. def applicationModule(): GuiceModule = createModule() def createModule(): GuiceModule = { import scala.collection.JavaConverters._ val injectorModule = GuiceableModule.guice(Seq( bind[PlayInjector].to[GuiceInjector], bind[play.inject.Injector].to[play.inject.DelegateInjector] ), binderOptions) val enabledModules = modules.map(_.disable(disabled)) val bindingModules = GuiceableModule.guiced(environment, configuration val overrideModules = GuiceableModule.guiced(environment, configuratio GuiceModules.`override`(bindingModules.asJava).`with`(overrideModules. } 44
  • 45. GuiceInjector GuiceInjector Guice Injector instanceOf[T] injector().instanceOf[Application] class GuiceInjector @Inject() ( injector: com.google.inject.Injector ) extends PlayInjector { def instanceOf[T](implicit ct: ClassTag[T]) = instanceOf(ct.runtimeClass def instanceOf[T](clazz: Class[T]) = injector.getInstance(clazz) def instanceOf[T](key: BindingKey[T]) = injector.getInstance(GuiceKey } 45
  • 46. Application Guice Injector con g framework/src/play/src/main/resources/reference .conf play { modules { # The enabled modules that should be automatically loaded. enabled += "play.api.inject.BuiltinModule" # enabled += "play.api.i18n.I18nModule" # A way to disable modules that are automatically enabled disabled = [] } } 46
  • 47. play.api.inject.BuiltinModule Provider class BuiltinModule extends Module { def bindings(env: Environment, configuration: Configuration): Seq[ // ... ... Seq( bind[Environment] to env, bind[Configuration].toProvider[ConfigurationProvider], bind[DefaultApplicationLifecycle].toSelf, bind[ApplicationLifecycle].to(bind[DefaultApplicationLifecycle bind[Application].to[DefaultApplication], // bind[play.Application].to[play.DefaultApplication], bind[ActorSystem].toProvider[ActorSystemProvider], bind[Materializer].toProvider[MaterializerProvider], bind[ExecutionContext].to[ExecutionContextExecutor], // ... ... } 47
  • 48. DefaultApplication Inject @Singleton class DefaultApplication @Inject() ( environment: Environment, applicationLifecycle: DefaultApplicationLifecycle, override val injector: Injector, override val configuration: Configuration, override val requestHandler: HttpRequestHandler, override val errorHandler: HttpErrorHandler, override val actorSystem: ActorSystem, override val materializer: Materializer) extends Application { def path = environment.rootPath def classloader = environment.classLoader def mode = environment.mode def stop() = applicationLifecycle.stop() } 48
  • 49. src // 3. Start the application val application: Application = { val environment = Environment(config.rootDir, process.classLoader, Mode.Prod) val context = ApplicationLoader.createContext(environment) val loader = ApplicationLoader(context) loader.load(context) } // Play.start(application) 49
  • 50. play.api.Play#start @volatile private[play] var _currentApp: Application = _ def start(app: Application) { stop(_currentApp) _currentApp = app Threads.withContextClassLoader(app.classloader) { app.global.beforeStart(app) app.routes app.global.onStart(app) } app.mode match { case Mode.Test => // started case mode => logger.info("Application started (" + mode + ")") } } 50
  • 52. HTTP netty src ServerProvider Server hook PID val serverProvider: ServerProvider = ServerProvider.fromConfiguration( process.classLoader, config.configuration ) val server = serverProvider.createServer(config, application) process.addShutdownHook { server.stop() pidFile.foreach(_.delete()) assert(!pidFile.exists(_.exists), "PID file should not exist!") } server 52
  • 53. ServerProvider#fromCon guration play.server.provider new framework/src/play-netty- server/src/main/resources/reference.conf play.core.server.NettyServerProvider akka-http experimental def fromConfiguration(classLoader: ClassLoader, configuration: Configurati val ClassNameConfigKey = "play.server.provider" val className: String = configuration.getString(ClassNameConfigKey val clazz = try classLoader.loadClass(className) catch { // } val ctor = try clazz.getConstructor() catch { // } ctor.newInstance().asInstanceOf[ServerProvider] } 53
  • 54. NettyServerProvider#createServer play.core.server.NettyServer new def createServer(context: ServerProvider.Context) = new NettyServer( context.config, context.appProvider, context.stopHook, context.actorSystem )( context.materializer ) 54
  • 55. NettyServer val bind new src class NettyServer(/* */) { // Maybe the HTTP server channel private val httpChannel = config.port.map(bindChannel(_, secure = false)) // Maybe the HTTPS server channel private val httpsChannel = config.sslPort.map(bindChannel(_, secure = true)) private def bindChannel(port: Int, secure: Boolean): Channel = { val protocolName = if (secure) "HTTPS" else "HTTP" val address = new InetSocketAddress(config.address, port) val (serverChannel, channelSource) = bind(address) channelSource.runWith(channelSink(port = port, secure = secure)) /* */ } } 55
  • 56. NettyServer#bind netty akka-stream Source HTTP Source OK Source => Sink private def bind(address: InetSocketAddress): (Channel, Source[Channel val serverChannelEventLoop = eventLoop.next // Watches for channel events, and pushes them through a reactive stre val channelPublisher = new HandlerPublisher(serverChannelEventLoop, cl /* */ val channel = bootstrap.bind.await().channel() allChannels.add(channel) (channel, Source.fromPublisher(channelPublisher)) } 56
  • 57. NettyServer#channelSink input(Source) Sink PlayRequestHandler val (serverChannel, channelSource) = bind(address) // channelSource.runWith(channelSink(port = port, secure = secure)) // : private def channelSink(port: Int, secure: Boolean): Sink[Channel, Future Sink.foreach[Channel] { (connChannel: Channel) => val pipeline = connChannel.pipeline() /* ... */ pipeline.addLast("decoder", new HttpRequestDecoder(maxInitialLineLengt val requestHandler = new PlayRequestHandler(this) // pipeline.addLast("http-handler", new HttpStreamsServerHandler(Seq pipeline.addLast("request-handler", requestHandler)      /* ... */ } } 57
  • 58. NettyServer akka-stream netty (Source/Sink) play.server.netty.transport native epoll (Linux) PlayRequestHandler ( private lazy val transport = conf.getString("transport") match { case "native" => Native case "jdk" => Jdk } 58
  • 59. 59
  • 61. Typsafe Con g/Google Guice/JBoss Netty/Akka/Akka-Stream sbt run ProdServer 61
  • 62. 62
  • 63. 63
  • 64. PlayRequestHandler ChannelInboundHandlerAdapter netty class Netty def channelRead def handle private[play] class PlayRequestHandler( val server: NettyServer ) extends ChannelInboundHandlerAdapter { // ... override def channelRead(ctx: ChannelHandlerContext, msg: Object): // Handle the given request. def handle( channel: Channel, request: HttpRequest ): Future[HttpResponse] = { /* */ } } 64
  • 65. PlayRequestHandler.channelRead Netty HttpRequest handle Write trampoline ExecutionContext override def channelRead(ctx: ChannelHandlerContext, msg: Object): Unit logger.trace(s"channelRead: ctx = ${ctx}, msg = ${msg}") msg match { case req: HttpRequest => requestsInFlight.incrementAndGet() /* handle */ val future: Future[HttpResponse] = handle(ctx.channel(), req) import play.api.libs.iteratee.Execution.Implicits.trampoline lastResponseSent = lastResponseSent.flatMap { /* */ ctx.writeAndFlush(httpResponse) /* Write */ } } } 65
  • 66. PlayRequesthHandler.handle NettyModelConversion Netty io.netty.handler.codec.http.HttpRequest Play play.api.mvc.RequestHeader Try[RequestHeader] def handle( channel: Channel, request: HttpRequest ): Future[HttpResponse] = { import play.api.libs.iteratee.Execution.Implicits.trampoline val requestId = RequestIdProvider.requestIDs.incrementAndGet() // val tryRequest = modelConversion.convertRequest( requestId, channel.remoteAddress().asInstanceOf[InetSocketAddress], Option(channel.pipeline().get(classOf[SslHandler])), request ) } 66
  • 67. PlayRequestHandler.handle Success server.getHandlerFor Right Application handler Left Result val (requestHeader, resultOrHandler) = tryRequest match { case Failure(exception: TooLongFrameException) => clientError(Status case Failure(exception) => clientError(Status.BAD_REQUEST, exception.g case Success(untagged) => server.getHandlerFor(untagged) match { case Left(directResult) => untagged -> Left(directResult) case Right((taggedRequestHeader, handler, application)) => taggedRequestHeader -> Right((handler, application)) } } 67
  • 68. play.core.server.Server#getHandleFor Handler Right Handler Left Result WebCommand Left Result DefaultHttpRequestHandler handleForRequest def getHandlerFor( request: RequestHeader ): Either[Future[Result], (RequestHeader, Handler, Application)] = { /* */ application.requestHandler.handlerForRequest(request) match { case (requestHeader, handler) => Right((requestHeader, handler, applic } } 68
  • 69. DefaultHttpRequestHandler#handleForReque st HEAD GET def handlerForRequest(request: RequestHeader) = { /* ... */ val (routedRequest, handler) = routeRequest(request) map { case handler: RequestTaggingHandler => (handler.tagRequest(request), handler) case otherHandler => (request, otherHandler) } getOrElse { // We automatically permit HEAD requests against any GETs without the // add an explicit mapping in Routes request.method match { case HttpVerbs.HEAD => routeRequest(request.copy(method = HttpVerbs.GET)) match { /* */ /* */ (routedRequest, filterHandler(rh => handler)(routedRequest)) } 69
  • 70. routeRequest, Router, RoutesProvider class DefaultHttpRequestHandler { def routeRequest(request: RequestHeader): Option[Handler] = { router.handlerFor(request) } } trait Router { def handlerFor(request: RequestHeader): Option[Handler] = { routes.lift(request) } } class RoutesProvider { /* */ lazy val get = { val prefix = httpConfig.context val router = Router.load(environment, configuration) .fold[Router](Router.empty)(injector.instanceOf(_)) router.withPrefix(prefix) } } 70
  • 72. routes.Routes conf/routes routes-compiler target/scala-2.11/routes/main/router/Routes.scala // Scala class Routes( override val errorHandler: play.api.http.HttpErrorHandler, // @LINE:6 HomeController_0: controllers.HomeController, // @LINE:8 CountController_3: controllers.CountController, // @LINE:10 AsyncController_2: controllers.AsyncController, // @LINE:13 Assets_1: controllers.Assets, val prefix: String ) extends GeneratedRouter 72
  • 73. Rourtes.routes RequestHeader Handler PartialFunction def routes: PartialFunction[RequestHeader, Handler] = { // @LINE:6 case controllers_HomeController_index0_route(params) => call { controllers_HomeController_index0_invoker.call( HomeController_0.index ) } // @LINE:8 case controllers_CountController_count1_route(params) => call { controllers_CountController_count1_invoker.call( CountController_3.count ) } /* */ } 73
  • 74. Handler src val (requestHeader, resultOrHandler) = /* */ resultOrHandler match { //execute normal action case Right((action: EssentialAction, app)) => val recovered = EssentialAction { rh => import play.api.libs.iteratee.Execution.Implicits.trampoline action(rh).recoverWith { case error => app.errorHandler.onServerError(rh, error) } } handleAction(recovered, requestHeader, request, Some(app)) /* */ } EssentialAction EssentialAction { rh => action(rh) 74
  • 75. EssentialAction app/controllers/HomeController.scala package controllers import javax.inject.{ Inject, Singleton } import play.api.mvc.{ Controller, Action, AnyContent } @Singleton class HomeController @Inject() extends Controller { def index: Action[AnyContent] = Action { req => Ok(views.html.index("Your new application is ready.")) } } conf/routes GET / controllers.HomeController.index GET /count controllers.CountController.count GET /message controllers.AsyncController.message 75
  • 76. Controller Action def index: Action[AnyContent] = Action { req => Ok(views.html.index("Your new application is ready.")) } Action { req => object Action apply trait Action[A] A Action Action[JsValue] JSON req Request[A] A Request Result 76
  • 77. Action BodyParser Action[A] BodyParser[A] BodyParser[A] A RequestHeader -> RequestBody(Array[Byte]) -> Result RequestBody Asynchornous Stream InputStream Akka- stream 77
  • 78. Accumulator[ByteString, Result] Action RequestHeader => Body => Result Accumulator RequestHeader => Accumulator[ByteString, Result] Accumulator Akka-stream(Source) ByteString Array[Byte] ( Akka ) Async Async FW 78
  • 79. Action[A] Action[A] Result RequestHeader => Accumulator[ByteString, Result] Play What is EssentialAction What is BodyParser 79
  • 80. EssentialAction EssentialAction Handler MixIn Action EssentialAction EssentialAction RequestHeader => Accumulator[ByteString, Result] trait EssentialAction extends (RequestHeader => Accumulator[ByteString, Result]) with Handler { self => def apply() = this } trait Action[A] extends EssentialAction 80
  • 81. : Function Function trait Function1[-T1, +R] RequestHeader => Accumulator[ByteString, Result] Funtion1[RequestHeader, Accumulator[ByteString, Result]] // Intellij -T1 => R trait EssentialAction extends Function1[RequestHeader, Accumulator[ByteString, Result]] 81
  • 82. Action#apply BodyParser def apply(request: Request[A]): Future[Result] = { /* */ } // def apply(rh: RequestHeader): Accumulator[ByteString, Result] = parser(rh).mapFuture { // parser BodyParser case Left(r) => /* ... (T_T) */ case Right(a) => /* */ val request = Request(rh, a) apply(request) // apply }(executionContext) 82
  • 83. PlayRequestHandler resultOrHandler match { //execute normal action case Right((action: EssentialAction, app)) => val recovered = EssentialAction { rh => import play.api.libs.iteratee.Execution.Implicits.trampoline // action(rh) Accumulator action(rh).recoverWith { case error => app.errorHandler.onServerError(rh, error) } } // handleAction(recovered, requestHeader, request, Some(app)) /* */ } 83
  • 84. handleAction Action private def handleAction(action: EssentialAction, requestHeader: RequestHe request: HttpRequest, app: Option[Application]): Future[HttpResponse for { bodyParser <- Future(action(requestHeader))(mat.executionContext) actionResult <- { val body = modelConversion.convertRequestBody(request) (body match { case None => bodyParser.run() case Some(source) => bodyParser.run(source) }).recoverWith { /* ... */ } } validatedResult <- { /* Clean and validate the action's result */ convertedResult <- { /* Netty HttpResponse */ modelConversion.convertResult(validatedResult, requestHeader, reques } } yield convertedResult } 84
  • 85. handleAction bodyParser Action apply Accumulator[ByteString, Result] body Netty Accumulator run actionResult Result Ok Result Netty HttpResponse 85
  • 86. src HttpResponse writeAndFlush override def channelRead(ctx: ChannelHandlerContext, msg: Object): Unit msg match { case req: HttpRequest => requestsInFlight.incrementAndGet() val future: Future[HttpResponse] = handle(ctx.channel(), req) /* handle */ /* */ import play.api.libs.iteratee.Execution.Implicits.trampoline lastResponseSent = lastResponseSent.flatMap { /* */ ctx.writeAndFlush(httpResponse) } } } 86
  • 87. 87
  • 88. 88