Tornado 高并发源码分析之三--- Application 对象

Application 对象主要工作:

服务器启动时:

1、在新建一个app的时候,根据设置好的 URL 和回调函数 Handler 封装成URLSpec 对象

服务器运行时:

2、在请求到来,将 HTTPServer 封装好的HTTPRequest 传入_RequestDispatcher对象,_RequestDispatcher对象根据传入的 HTTPRequest 使用URLSpec解析匹 match 正则匹配找到对应的 RequestHandler ,执行它的 _execute 方法

Application设计优点

1、Application 本身不处理数据,只是封装 URL , 解析请求的 URL, 分发到 URL 相对应的 RequestHandler 去执行具体操作

以下为源码分析,省略了一部分代码,只取关键部分显示

 1 class Application(httputil.HTTPServerConnectionDelegate):
 2 # 继承自httputil.HTTPServerConnectionDelegate, 其实HTTPServerConnectionDelegate只是一种类似于协议的东西,只要继承自他就可以了,方便其他地方可以调用 isinstanct 来判断,
 3 def __init__(self, handlers=None, default_host="", transforms=None, **settings):
 4 #完成 url映射 和 setting相关的设置
 5
 6     self.handlers = []
 7     self.named_handlers = {}
 8     self.settings = settings   #导入设置的参数
 9
10     if handlers:
11         self.add_handlers(".*$", handlers)     #将URL 和 Handler 映射封装成 URLSpec 对象
12
13     if self.settings.get(‘autoreload‘):   #设置自动重启
14         from tornado import autoreload
15         autoreload.start()
16
17
18 def add_handlers(self, host_pattern, host_handlers):
19          #将 url 和 handler 封装成URLSpec
20     for spec in host_handlers:
21         if isinstance(spec, (tuple, list)):
22             assert len(spec) in (2, 3, 4)
23             spec = URLSpec(*spec)   #封装成 URLSpec 对象
24         handlers.append(spec)
25         if spec.name:
26             if spec.name in self.named_handlers:
27                 app_log.warning(
28                     "Multiple handlers named %s; replacing previous value",
29                     spec.name)
30             self.named_handlers[spec.name] = spec   #将url 和 handler隐射封装起来
31
32 def __call__(self, request):
33     # 在这里巧用了__call__方法,当一个application 新建的时候,将会被动调用,这个是在请求信息已经接收完毕,已经封装成 HTTPRequest 对象之后,执行用户的 RequestHandler 对象的get、post方法
34     dispatcher = _RequestDispatcher(self, None)
35     dispatcher.set_request(request)   #将封装好的HTTPRequest对象(此时数据已经接收完毕),设置进_RequestDispatcher中,
36     return dispatcher.execute()  #执行用户的 RequestHandler 对象的get、post方法,对数据处理,并返回
 1 class _RequestDispatcher(httputil.HTTPMessageDelegate):
 2 正在用来执行用户写的 RequestHandler 对象里面的get、post等方法
 3 def set_request(self, request):
 4     self.request = request  #设置request
 5     self._find_handler()   #根据request查找url匹配
 6     self.stream_request_body = _has_stream_request_body(self.handler_class)
 7
 8 def _find_handler(self):
 9 #
10     app = self.application
11     handlers = app._get_host_handlers(self.request)   #从request中获取头信息
12     if not handlers:
13         self.handler_class = RedirectHandler
14         self.handler_kwargs = dict(url="http://" + app.default_host + "/")
15         return
16     for spec in handlers:  #遍历url 匹配的类
17         match = spec.regex.match(self.request.path)  #url路径匹配
18         if match:
19             self.handler_class = spec.handler_class  #获取url匹配的我们写的自定义的RequestHandler类
20             self.handler_kwargs = spec.kwargs
21             if spec.regex.groups:
22                 if spec.regex.groupindex:
23                     self.path_kwargs = dict(
24                         (str(k), _unquote_or_none(v))
25                         for (k, v) in match.groupdict().items())
26                 else:
27                     self.path_args = [_unquote_or_none(s)
28                                       for s in match.groups()]
29             return
30
31
32 def execute(self):
33     self.handler = self.handler_class(self.application, self.request, **self.handler_kwargs)   #获取我们自定义的RequestHandler类实例,传递参数
34
35     if self.stream_request_body:   #先创建一个future 对象
36         self.handler._prepared_future = Future()
37
38     self.handler._execute(transforms, *self.path_args, **self.path_kwargs)   #执行我们自定义的,继承RequestHandler类的 _execute 函数, 所以最后我们的写的get post方法,还是在自己的那个类的_execute方法中调用执行的
39
40     return self.handler._prepared_future   #返回自定义的RequestHandler future 对象
时间: 2024-08-01 20:44:08

Tornado 高并发源码分析之三--- Application 对象的相关文章

Tornado 高并发源码分析之四--- HTTPServer 与 TCPServer 对象

主要工作: 服务器启动的时候做的事: 1.把包含了各种配置信息的 application 对象封装到了 HttpServer 对象的 request_callback 字段中,等待被调用 2.TCPServer 通过 listen 方法启动端口监听, 封装_handle_connection回调函数,并注册到 IOLoop 中 服务器运行时做的事: 3.当有请求到来时,注册在 IOLoop 中的 _handle_connection 将会被调用, _handle_connection 方法将会调

Tornado 高并发源码分析之一---启动一个web服务

前言: 启动一个tornado 服务器基本代码 1 class HomeHandler(tornado.web.RequestHandler): #创建 RequesHandler 对象,处理接收到的 http 请求 2 def get(self): 3 entries = self.db.query("SELECT * FROM entries ORDER BY published DESC LIMIT 5") 4 if not entries: 5 self.redirect(&q

Tornado 高并发源码分析之二---Tornado启动和请求处理流程

Tornado 服务器启动流程 因为Tornado 里使用了很多传类的方式,也就是delegate,之所以要这么做,其实和 iOS 开发那样,也很多的 delegate, 如此来实现高度解耦,但是比较绕,所以建议: 1.先浏览一遍启动流程,再看源码 2.在看一遍请求到来时的处理流程,再看源码 备注: 流程图是xmind 编辑的,好像这里无法上传源文件,所以只能把图片下载下来看了,会没那么清晰

Tornado 高并发源码分析之六---异步编程的几种实现方式

方式一:通过线程池或者进程池 导入库futures是python3自带的库,如果是python2,需要pip安装future这个库 备注:进程池和线程池写法相同 1 from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor 2 from tornado.concurrent import run_on_executor 3 4 def doing(s): 5 print('xiumian--{}'.format(

Tornado Etag实现源码分析

Etag(URL的Entity Tag): 对于具体Etag是什么,请求流程,实现原理,这里不进行介绍,可以参考下面链接: http://www.oschina.net/question/234345_42536?sort=time https://zh.wikipedia.org/wiki/HTTP_ETag Tornado实现分析: 先从Tornado处理一个请求的调用顺序开始看(摘自文档:http://www.tornadoweb.cn/documentation): 程序为每一个请求创建

Hybrid开发源码分析之safe-java-js-webview-bridge

周末抽空看了了下safe-java-js-webview-bridge的源码,整理了一份类之间的调用关系图. 该开源库的基本思路分三步: 1.在native端编写调用本地功能的class(如HostJsScope.java),在初始化WebviewChromeClient时根据该class(在JsCallJava构造函数中)反射动态生成js代码: 2.将动态生成的js代码通过webview.loadUrl触发的onProgressChanged注入到webview中,供前端可调用: 3.在前端调

LinkedList插入数据效率不一定比ArrayList高,源码分析+实验对比

(一)结论 在尾部插入数据,数据量较小时LinkedList比较快,因为ArrayList要频繁扩容,当数据量大时ArrayList比较快,因为ArrayList扩容是当前容量*1.5,大容量扩容一次就能提供很多空间,当ArrayList不需扩容时效率明显比LinkedList高,因为直接数组元素赋值不需new Node 在首部插入数据,LinkedList较快,因为LinkedList遍历插入位置花费时间很小,而ArrayList需要将原数组所有元素进行一次System.arraycopy 插

原创:Twemproxy源码分析之三:其进程以及时间模型

概述:本来自己写了一篇,但是看到http://www.tuicool.com/articles/NfqeEf这篇更好,于是就算转载过来了吧.下一篇我们会讲到twemproxy的核心,即其转发响应转发请求. 作为一个proxy服务,我们应该深入了解它的进程和事件模型. 进程模型: 通过grep代码,查找fork()和pthread_create()函数的调用,并分析调用者两个函数的代码.我们可以看到twemproxy使用的是单进程单线程来处理请求,另外有一个线程来处理统计数据,但并不参与处理请求功

TodoMVC中的Backbone+MarionetteJS+RequireJS例子源码分析之三 Views

这个版本的TodoMVC中的视图组织划分比较细,更加易于理解,这也得益于Marionette为我们带来了丰富的视图选择,原生的backbone只有views,而Marionette则有itemview, collectionview, compositeview 和layoutview. js/templates.js /*global define */ define(function (require) {//这里用了简写,因为require.js是CommonJS 模块,相当于 defin