flask源码分析

入口

image-20230406184619998

image-20230406184727093

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

image-20230406222715601

image-20230406185503261

image-20230406191410516

然后去看 wsgi_app

image-20230406191506019

image-20230406191636740

image-20230406191811397

image-20230406191903555

image-20230406192028881

image-20230406192122491

image-20230406192233134

image-20230406193640703

image-20230406193708002

image-20230406193754895

image-20230406193828807

image-20230406193903426

image-20230406194117972

image-20230406202637556

然后回来

image-20230406202712767

image-20230406194652859

image-20230406201613425

image-20230406201642842

image-20230406201715847

image-20230406201759054

image-20230406201820162

image-20230406201943690

image-20230406202138236

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

image-20230406202314430

image-20230406203952617

image-20230406204028792

image-20230406204113298

image-20230406204136829

image-20230406204307832

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

image-20230406204704002

image-20230406204724639

image-20230406204840705

image-20230406210032698

image-20230406211418842

image-20230406211854381

image-20230406211259790

image-20230406210221103

image-20230406210513787

def add_url_rule(
    self,
    rule,
    endpoint=None,
    view_func=None,
    provide_automatic_options=None,
    **options
):
        self.view_functions[endpoint] = view_func

这个就是我们添加路由的时候 把我们的视图函数添加进去了

image-20230406211147338

image-20230406211544906

image-20230406211648871

image-20230406211753068

详细说一下Local()

image-20230406202958431

image-20230406203213675

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

image-20230406203426632

image-20230406203902632

补充

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()

image-20230406220700993

可以看出 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
posted @ 2023-04-06 22:03  可否  阅读(55)  评论(1)    收藏  举报