從tornado的 Hello,world 開始分析tornado的原始碼
python
import 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__
簡化版程式碼:
python
def __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的具體用法
- 初始化transforms(HTTP傳輸壓縮等,預設GZipContentEncoding 和 ChunkedTransferEncoding 。也可以自己實現,需要實現 transform_first_chunk 和 transform_chunk 介面,RequestHandler 中的 flush 呼叫,剖析RequestHandler時詳細介紹),UI模組
- 通過settings的值來初始化靜態檔案處理Handler,包括:
- static_path
- static_url_prefix
- static_handler_class
- static_handler_args
- static_hash_cache
- 初始化其他settings
- 呼叫
add_handlers
方法新增handlers。 - 載入自動重新載入模組(當檢測到程式碼被修改後重構啟動)
二、add_handle
python
def 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的listen
和tornado.ioloop.IOLoop.instance().start()
(以後會詳細介紹ioloop),來真正啟動。
三、listen
python
def 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
建立的規則。