LoginSignup
67
58

More than 5 years have passed since last update.

Revelの主な処理の流れ

Last updated at Posted at 2014-08-29

Go製フレームワークRevelの処理の流れです。
ざっくりとした処理の流れの話です。

以下、社内勉強会用資料。

revelの主な処理の流れ

RevelDesign.png
http://revel.github.io/manual/concepts.html

Play Frameworkを参考に作っている。
基本的にはMVC。

revel アプリの作成方法

revel アプリケーションの作成

$ revel new sample
~
~ revel! http://revel.github.io
~
Your application is ready:
   /Users/username/.go/src/sample

You can run it with:
   revel run sample

$GOPATH/src/sample のファイル構成

.
├── app
│   ├── controllers
│   │   └── app.go
│   ├── init.go
│   └── views
│       ├── App
│       │   └── Index.html
│       ├── debug.html
│       ├── errors
│       │   ├── 404.html
│       │   └── 500.html
│       ├── flash.html
│       ├── footer.html
│       └── header.html
├── conf
│   ├── app.conf
│   └── routes
├── messages
│   └── sample.en
├── public
│   ├── css
│   │   └── bootstrap.css
│   ├── img
│   │   ├── favicon.png
│   │   ├── glyphicons-halflings-white.png
│   │   └── glyphicons-halflings.png
│   └── js
│       └── jquery-1.9.1.min.js
└── tests
    └── apptest.go

revel の実行

$ revel run sample

起動してアクセスをすると、app/routes/routes.goapp/tmp/main.go にファイルが作られている。

.
├── app
│   ├── controllers
│   │   └── app.go
│   ├── init.go
│   ├── routes # ここと
│   │   └── routes.go
│   ├── tmp    # ここが新しい
│   │   └── main.go
│   └── views
# 省略

revel の内部構造

revel.png

https://github.com/hirokidaichi/goviz で出力

各構成

  • main: コマンドツール
  • harness: アプリケーションのビルドやwatchなどを行う
  • revel: コア
  • config: コンフィグ設定
  • websocket: websocket
  • pathtree: routerのマッチング /:userId のマッチング
  • simpleuuid: uuid生成
  • fsnotify: fileのwatchで利用
  • gocolorize: コンソールに色つけ

Harness

  • ユーザープログラムをパースして、起動コントローラとなるmain.goを生成して、ユーザーアプリケーションサーバーを起動する
  • ユーザープログラムのbuildとrun。コンパイルエラーの表示。
  • rebuildやモニタリングもここ経由で表示

watch

  • app側の config/app.conf のwatchの状態によって、harness側の挙動が変わる
    • harness用のport開いたり

build

github.com/revel/revel/harness/build.go 内でビルドしている.

// Generate two source files.
templateArgs := map[string]interface{}{
     "Controllers":    sourceInfo.ControllerSpecs(),
     "ValidationKeys": sourceInfo.ValidationKeys,
     "ImportPaths":    calcImportAliases(sourceInfo),
     "TestSuites":     sourceInfo.TestSuites(),
}

genSource("tmp", "main.go", MAIN, templateArgs)
genSource("routes", "routes.go", ROUTES, templateArgs)

https://github.com/revel/revel/blob/master/harness/build.go#L288 にmain.go。
https://github.com/revel/revel/blob/master/harness/build.go#L341 にroutes.goのテンプレートがある

main.go作成後

github.com/revel/revel/harness/app.go 側からオプションを渡してmain.goを実行

github.com/revel/revel/harness/app.go
// AppCmd manages the running of a Revel app server.
// It requires revel.Init to have been called previously.
type AppCmd struct {
  *exec.Cmd
}

//
// (省略)
//

// Run the app server inline.  Never returns.
func (cmd AppCmd) Run() {
  revel.TRACE.Println("Exec app:", cmd.Path, cmd.Args)
  if err := cmd.Cmd.Run(); err != nil {
    revel.ERROR.Fatalln("Error running:", err)
  }
}

main.go側の処理

github.com/revel/revel/server.gofunc Run() があり、なんだかんだでそれが走る。

リクエストを受け付けると handlerが実行され
revel.Controllerとrevel.Request, revel.Responseが作成されて
各Filtersを実行していく。

Filters

revel newを実行したときのアプリケーションのScaffoldの
app/init.go にfiltersが設定されている。

RevelDesign.png
http://revel.github.io/manual/concepts.html

app/init.go
func init() {
  // Filters is the default set of global filters.
  revel.Filters = []revel.Filter{
    revel.PanicFilter,             // Recover from panics and display an error page instead.
    revel.RouterFilter,            // Use the routing table to select the right Action
    revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
    revel.ParamsFilter,            // Parse parameters into Controller.Params.
    revel.SessionFilter,           // Restore and write the session cookie.
    revel.FlashFilter,             // Restore and write the flash cookie.
    revel.ValidationFilter,        // Restore kept validation errors and save new ones from cookie.
    revel.I18nFilter,              // Resolve the requested language
    HeaderFilter,                  // Add some security based headers
    revel.InterceptorFilter,       // Run interceptors around the action.
    revel.CompressFilter,          // Compress the result.
    revel.ActionInvoker,           // Invoke the action.
  }

  // register startup functions with OnAppStart
  // ( order dependent )
  // revel.OnAppStart(InitDB)
  // revel.OnAppStart(FillCache)
}

revel.ActionInvokerがコントローラの特定のアクション実行のトリガー。
最終的にc.Resultにactionの結果が入る(テンプレじゃないよ)

github.com/revel/revel/server.go
func handleInternal(w http.ResponseWriter, r *http.Request, ws *websocket.Conn) {
  var (
    req  = NewRequest(r)
    resp = NewResponse(w)
    c    = NewController(req, resp)
  )
  req.Websocket = ws

  Filters[0](c, Filters[1:]) // ここで各フィルターが実行 & 最後にアクション実行
  if c.Result != nil {
    c.Result.Apply(req, resp)
  } else if c.Response.Status != 0 {
    c.Response.Out.WriteHeader(c.Response.Status)
  }
  // Close the Writer if we can
  if w, ok := resp.Out.(io.Closer); ok {
    w.Close()
  }
}

結果の整形、ジェネレート

  • 返ってくる Resultの型によって、最終的に返すstringを変えている

Resultのインターフェース

type Result interface {
  Apply(req *Request, resp *Response)
}

Resultsの構造体

type ErrorResult struct {
type PlaintextErrorResult struct {
type RenderTemplateResult struct {
type RenderHtmlResult struct {
type RenderJsonResult struct {
type RenderXmlResult struct {
type RenderTextResult struct {
type ContentDisposition string
type BinaryResult struct {
type RedirectToUrlResult struct {
type RedirectToActionResult struct {

RenderTemplateResult の場合

特に何もしないとRenderTemplateResultが利用される。
https://github.com/revel/revel/blob/master/results.go#L165
templateを使ってhtmlを生成している。

それをResponseにしこんで1リクエストの処理が完了する。

話してないこと

  • Routerの挙動
  • watch時の挙動
  • 各Filterの挙動
  • ActionInvoker実行時のBinderについて
  • Interceptors
  • Validation
67
58
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
67
58