【Tornado原始碼閱讀筆記】tornado.web.Application

mtunique發表於2015-01-03

從tornado的 Hello,world 開始分析tornado的原始碼

pythonimport tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

application = tornado.web.Application([
    (r"/", MainHandler),
])

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

很容易可以看出,通過繼承RequestHandler類定義自己的處理類,來處理請求。Application類的物件來處理URI的路由(將URIr"/"於處理類MainHandler組成tuple,關聯起來)。

tornado.web.Application類

一、__init__

簡化版程式碼:

pythondef __init__(self, handlers=None, default_host="", transforms=None,
             **settings):
    if transforms is None:
        self.transforms = []
        if settings.get("compress_response") or settings.get("gzip"):
            self.transforms.append(GZipContentEncoding)
    else:
        self.transforms = transforms
    ......
    self.ui_modules = {`linkify`: _linkify,
                       `xsrf_form_html`: _xsrf_form_html,
                       `Template`: TemplateModule,
                       }
    self.ui_methods = {}
    self._load_ui_modules(settings.get("ui_modules", {}))
    self._load_ui_methods(settings.get("ui_methods", {}))

    if self.settings.get("static_path"):
        ......
    if handlers:
        self.add_handlers(".*$", handlers)

    if self.settings.get(`debug`):
        self.settings.setdefault(`autoreload`, True)
        ......
    # Automatically reload modified modules
    if self.settings.get(`autoreload`):
        from tornado import autoreload
        autoreload.start()

引數handlers是一個list,list裡每個object是一個URLSpec的物件或tuple。tuple可以是二到四個element,分別是URI的正則、handler類、用於初始化URLSpec的kwargs、handler的name。
(下面add_handlers詳細說明)

引數settings是一個dict,所有settings的具體用法

  1. 初始化transforms(HTTP傳輸壓縮等,預設GZipContentEncoding 和 ChunkedTransferEncoding 。也可以自己實現,需要實現 transform_first_chunk 和 transform_chunk 介面,RequestHandler 中的 flush 呼叫,剖析RequestHandler時詳細介紹),UI模組
  2. 通過settings的值來初始化靜態檔案處理Handler,包括:
    • static_path
    • static_url_prefix
    • static_handler_class
    • static_handler_args
    • static_hash_cache
  3. 初始化其他settings
  4. 呼叫add_handlers方法新增handlers。
  5. 載入自動重新載入模組(當檢測到程式碼被修改後重構啟動)

二、add_handle

pythondef add_handlers(self, host_pattern, host_handlers):
    if not host_pattern.endswith("$"):
        host_pattern += "$"
    handlers = []
    if self.handlers and self.handlers[-1][0].pattern == `.*$`:
        self.handlers.insert(-1, (re.compile(host_pattern), handlers))
    else:
        self.handlers.append((re.compile(host_pattern), handlers))

    for spec in host_handlers:
        if isinstance(spec, (tuple, list)):
            assert len(spec) in (2, 3, 4)
            spec = URLSpec(*spec)
        handlers.append(spec)
        if spec.name:
            if spec.name in self.named_handlers:
                app_log.warning(
                    "Multiple handlers named %s; replacing previous value",
                    spec.name)
            self.named_handlers[spec.name] = spec

將host_pattern和handlers,組成tuple加到self.handlers的末尾但是在匹配所有域名的tuple前。

spec = URLSpec(*spec)易看出初始化Application的時候的第一個引數存的tuple是用來初始化URLSpec的所以引數順序應該和URLSpec要求的一樣(def __init__(self, pattern, handler, kwargs=None, name=None))。

用過第四個引數name來構造反響代理,儲存在Application的named_handlers(dict)裡。

hello world裡呼叫了Application的listentornado.ioloop.IOLoop.instance().start()(以後會詳細介紹ioloop),來真正啟動。

三、listen

pythondef listen(self, port, address="", **kwargs):
        from tornado.httpserver import HTTPServer
        server = HTTPServer(self, **kwargs)
        server.listen(port, address)

例項化一個HTTPServer,將application繫結上去。HTTPServer呼叫application的start_request來將application和connection繫結在一起初始化一個_RequestDispatcher的物件,由其來處理請求的路由,來利用add_handler建立的規則。

原文連線

相關文章