flask源码分析
入口


app加括号就会执行 Flask的双下__call__方法



然后去看 wsgi_app














然后回来









现在的 Local的__storage__ = {线程ID:{"stack":[AppContext对象,]}}






现在的 Local的__storage__ = {线程ID:{"stack":[AppContext对象,RequestContext对象]}}









def add_url_rule(
self,
rule,
endpoint=None,
view_func=None,
provide_automatic_options=None,
**options
):
self.view_functions[endpoint] = view_func
这个就是我们添加路由的时候 把我们的视图函数添加进去了




详细说一下Local()


以后 self.__ident_func__就是获取线程ID了


补充
pip3 install greenlet
from greenlet import getcurrent as get_id
from greenlet import greenlet
from threading import Thread, get_ident
aa = {}
def task():
print("我是%s" % get_id())
aa[get_id()] = None
print("我是%s" % get_ident())
if __name__ == '__main__':
t1 = greenlet(task)
t1.switch()
print(aa)
t = Thread(target=task)
t.start()

可以看出 get_id不仅可以获取线程的ID也可以获取协程的ID
# 请求来了---》app()----->Flask.__call__--->self.wsgi_app(environ, start_response)
def wsgi_app(self, environ, start_response):
# environ:http请求拆成了字典
# ctx对象:RequestContext类的对象,对象里有:当次的requets对象,app对象,session对象
ctx = self.request_context(environ)
error = None
try:
try:
#ctx RequestContext类 push方法
ctx.push()
# 匹配成路由后,执行视图函数
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except:
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
# RequestContext :ctx.push
def push(self):
# _request_ctx_stack = LocalStack() ---》push(ctx对象)--》ctx:request,session,app
_request_ctx_stack.push(self)
#session相关的
if self.session is None:
session_interface = self.app.session_interface
self.session = session_interface.open_session(self.app, self.request)
if self.session is None:
self.session = session_interface.make_null_session(self.app)
# 路由匹配相关的
if self.url_adapter is not None:
self.match_request()
# LocalStack() push --->obj 是ctx对象
def push(self, obj):
#self._local _local 就是咱们刚刚自己写的Local的对象---》LocalStack的init初始化的_local---》self._local = Local()---》Local对象可以根据线程协程区分数据
rv = getattr(self._local, "stack", None)
# 一开始没有值
if rv is None:
rv = []
self._local.stack = rv # self._local.stack 根据不同线程用的是自己的数据
rv.append(obj) # self._local.stack.append(obj)
# {'线程id号':{stack:[ctx]},'线程id号2':{stack:[ctx]}}
return rv
# 再往后执行,就会进入到路由匹配,执行视图函数
# request = LocalProxy(partial(_lookup_req_object, "request"))
# LocalProxy 代理类---》method---》代理类去当前线程的stack取出ctx,取出当时放进去的request
视图函数中:print(request.method)
# print(request) 执行LocalProxy类的__str__方法
# request.method 执行LocalProxy类的__getattr__
def __getattr__(self, name): #name 是method
# self._get_current_object() 就是当次请求的request
return getattr(self._get_current_object(), name)
# LocalProxy类的方法_get_current_object
def _get_current_object(self):
if not hasattr(self.__local, "__release_local__"):
return self.__local()
try:
return getattr(self.__local, self.__name__)
except AttributeError:
raise RuntimeError("no object bound to %s" % self.__name__)
# self.__local 是在 LocalProxy 类实例化的时候传入的local
# 在这里实例化的:request = LocalProxy(partial(_lookup_req_object, "request"))
# local 是 partial(_lookup_req_object, "request")
#_lookup_req_object ,name=request
def _lookup_req_object(name):
top = _request_ctx_stack.top # 取出了ctx,是当前线程的ctx
if top is None:
raise RuntimeError(_request_ctx_err_msg)
return getattr(top, name) #从ctx中反射出request,当次请求的request

浙公网安备 33010602011771号