11.6 Flask 源码流程,上下文管理

源码流程

创建对象

from flask import Flask 

"""
1 实例化对象 app
"""
app = Flask(__name__)

"""
2 设置路由
    将路由关系放在 app.url_map = {} 中
"""
@app.route("/index")
def index():
    return "index"

if —__name__ == "__main__":
"""
3 启动socket服务端
"""
    app.run()

"""
4 用户请求到来就会执行 __call__ 方法
"""

run

# 启动入口简约版代码
from werkzeug.wrappers import Response
from werkzeug.serving import run_simple

class Flask(object):
    def __call__(self,environ, start_response):
        response = Response(‘hello‘)
        return response(environ, start_response)

    def run(self):
        run_simple(‘127.0.0.1‘, 8000, self)

run_simple(host,port,self,**options)
会对第三个传入的参数加()进行执行
第三个参数如果是app对象就执行其 __call__ 方法

__call__

def __call__(self,environ, start_response):
    # environ 请求相关的所有数据 第一手的数据,由wsgi进行的初步封装
    # start_response 用于设置响应相关数据
    return wsgi_app(environ,start_response)

 call 返回的是 wsgi_app 的执行结果

wsgi_app

wsgi_app 里面做的事情就很多了。

我们一步一步来看

第一步 ctx 封装

首先把请求相关的所有数据都 封装了到 一个 ctx 对象

而且通过 __init__ 可以看到 封装了 request 以及创建了一个 空的 session 

第一步总结

  得到了 ctx 对象

  创建ctx.request 以及 ctx.session = None 

第二步 push

来看下 push 都做了什么

封了一个top,这是啥不知道,要继续看是个 LocalStack 对象

class LocalStack(object):

    """This class works similar to a :class:`Local` but keeps a stack
    of objects instead.  This is best explained with an example::

        >>> ls = LocalStack()
        >>> ls.push(42)
        >>> ls.top
        42
        >>> ls.push(23)
        >>> ls.top
        23
        >>> ls.pop()
        23
        >>> ls.top
        42

    They can be force released by using a :class:`LocalManager` or with
    the :func:`release_local` function but the correct way is to pop the
    item from the stack after using.  When the stack is empty it will
    no longer be bound to the current context (and as such released).

    By calling the stack without arguments it returns a proxy that resolves to
    the topmost item on the stack.

    .. versionadded:: 0.6.1
    """

    def __init__(self):
        self._local = Local()

    def __release_local__(self):
        self._local.__release_local__()

    def _get__ident_func__(self):
        return self._local.__ident_func__

    def _set__ident_func__(self, value):
        object.__setattr__(self._local, ‘__ident_func__‘, value)
    __ident_func__ = property(_get__ident_func__, _set__ident_func__)
    del _get__ident_func__, _set__ident_func__

    def __call__(self):
        def _lookup():
            rv = self.top
            if rv is None:
                raise RuntimeError(‘object unbound‘)
            return rv
        return LocalProxy(_lookup)

    def push(self, obj):
        """Pushes a new item to the stack"""
        rv = getattr(self._local, ‘stack‘, None)
        if rv is None:
            self._local.stack = rv = []
        rv.append(obj)
        return rv

    def pop(self):
        """Removes the topmost item from the stack, will return the
        old value or `None` if the stack was already empty.
        """
        stack = getattr(self._local, ‘stack‘, None)
        if stack is None:
            return None
        elif len(stack) == 1:
            release_local(self._local)
            return stack[-1]
        else:
            return stack.pop()

    @property
    def top(self):
        """The topmost item on the stack.  If the stack is empty,
        `None` is returned.
        """
        try:
            return self._local.stack[-1]
        except (AttributeError, IndexError):
            return None

LocalStack 源码

这个 LocalStack 对象是什么我们也还是不知道,还需需要继续看,发现其实是个 Local 对象

看到Local 到这里发现应该是看到底了,这样稍微看下 local 对象就是在 __storage__ 里面存了个数据结构

这个数据结构是这样的,

__storage__ = {
    线程/协程id:{}
    线程/协程id:{}
    线程/协程id:{}
}

class Local(object):
    __slots__ = (‘__storage__‘, ‘__ident_func__‘)

    def __init__(self):
        object.__setattr__(self, ‘__storage__‘, {})
        object.__setattr__(self, ‘__ident_func__‘, get_ident)

    def __iter__(self):
        return iter(self.__storage__.items())

    def __call__(self, proxy):
        """Create a proxy for a name."""
        return LocalProxy(self, proxy)

    def __release_local__(self):
        self.__storage__.pop(self.__ident_func__(), None)

    def __getattr__(self, name):
        try:
            return self.__storage__[self.__ident_func__()][name]
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        ident = self.__ident_func__()
        storage = self.__storage__
        try:
            storage[ident][name] = value
        except KeyError:
            storage[ident] = {name: value}

    def __delattr__(self, name):
        try:
            del self.__storage__[self.__ident_func__()][name]
        except KeyError:
            raise AttributeError(name)

Local 源码

然后我们在回头看下 LocalStark 是干嘛的, 原来这货是帮助维护这个数据结构的,

会把 Local 的数据进一步维护成这样

__storage__ = {
    线程/协程id:{stack:[ctx]}  # 维护成一个栈
    线程/协程id:{stack:[ctx]}
    线程/协程id:{stack:[ctx]}
    线程/协程id:{stack:[ctx]}
}    # 都是通过 Localstack 来操作 local 里面的数据结构

而且 LocalStark 里面还有一系列的操作方法,由此可见 LocalStark 应该就是专门操作 Local 对象数据的

ok,走到头了回去接着往下走

有封装了一个 app_ctx ,其实刚刚看 top 的时候就已经发现了 下面有个 app_ctx_stack  了

可见其实封装了两个 LocalStark 对象,分别是 请求相关的 以及 app相关的

然后继续往下走,这里分装了 app_ctx 是 AppContext 的 对象,

里面封装了,app 和 g

看到了这里

这里就是对 session 的操作了。之前的 session 一直是 空,这里进行真正的赋值。

可见 session 的赋值是通过配置文件的 配置名字 取到 session ,然后解密反序列化生成字典重新赋值 ctx.session 的具体操作实现

至此,push() 的代码看完了。

第二步总结

分装了 两个 ctx :

  - 请求上下文(ctx=RequestContext()):request/session
  - App上下文(app_ctx=AppContext()): app/g

  这两 ctx 都分别保存了两个 LocalStark 以及 两个 Local  

以及 赋值了 ctx.session

第三步 full_dispatch_request

这里就不详细看了。

大概做了两件事,执行了处理视图函数,以及一系列善后工作,

第四步 弹出请求对象

视图函数执行完毕后,一次请求结束,把请求的 ctx 对象弹出,

上下文管理

在看过了 整体的 Flask 的一次请求的流程之后,

我们再来分析上下文管理 ,直接看到这个比较重点的地方把

两个  LocalStack 对象,以及重要的 request,session 的产生的地方。

这里使用了 LocalProxy用于代理Local对象和LocalStack对象,以及偏函数

流程

程序启动

两个Local:
  local1 = {}

  local2 = {}

两个LocalStack:
  _request_ctx_stack
  _app_ctx_stack

请求到来

对数据进行封装:
    ctx = RequestContext(request,session)
    app_ctx = AppContext(app,g)
保存数据
    将包含了(app,g)数据的app_ctx对象,利用 _app_ctx_stack(LocalStack())将app_ctx添加到Local中
        storage = {
            1231:{stack:[app_ctx(app,g),]}
        }
     将包含了request,session数据的ctx对象,利用_request_ctx_stack(LocalStack()),将ctx添加到Local中
        storage = {
            1231:{stack:[ctx(request,session),]}
        }

视图函数处理

@app.route(‘/index‘)
def index():
    # 去请求上下文中获取值 _request_ctx_stack
    request.method
    session[‘xxx‘] 

    # 去app上下文中获取值:_app_ctx_stack
    print(current_app)
    print(g)

    return "Index"
方式一:直接找LocalStack获取
        from flask.globals import _request_ctx_stack
        print(_request_ctx_stack.top.request.method)

方式二:通过代理LocalProx获取
        from flask import Flask,request
        print(request.method)

请求结束

_app_ctx_stack.pop()
_request_ctx_stack.pop()

原文地址:https://www.cnblogs.com/shijieli/p/10355856.html

时间: 2024-08-29 09:01:05

11.6 Flask 源码流程,上下文管理的相关文章

Flask源码流程剖析

在此之前需要先知道类和方法,个人总结如下: 1.对象是类创建,创建对象时候类的__init__方法自动执行,对象()执行类的 __call__ 方法 2.类是type创建,创建类时候type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法) # 第0步: 执行type的 __init__ 方法[类是type的对象]class Foo:    def __init__(self):        pass def __c

Flask源码解析(理解working outside of application context)

from flask import Flask, current_app app = Flask(__name__) a = current_app d = current_app.config['DEBUG'] 首先从这段代码看起,代码运行的结果就是 RuntimeError: Working outside of application context. 此时本地代理未绑定,不是我们想要的核心flask对象.代码报错. current_app = LocalProxy(_find_app)

Tomcat7.0源码分析——Session管理分析(上)

前言 对于广大java开发者而已,对于J2EE规范中的Session应该并不陌生,我们可以使用Session管理用户的会话信息,最常见的就是拿Session用来存放用户登录.身份.权限及状态等信息.对于使用Tomcat作为Web容器的大部分开发人员而言,Tomcat是如何实现Session标记用户和管理Session信息的呢? 概述 Session Tomcat内部定义了Session和HttpSession这两个会话相关的接口,其类继承体系如图1所示. 图1 Session类继承体系图1中额外

【转】ANDROID自定义视图——onMeasure,MeasureSpec源码 流程 思路详解

原文地址:http://blog.csdn.net/a396901990/article/details/36475213 简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量——onMeasure():决定View的大小 2.布局——onLayout():决定View在ViewGroup中的位置 3.绘制——onDraw():如何绘制这个View. 而第3步的onDraw系统已经封装的很好了,基本不用我们来操心,只需要专注到1,2两个步骤就中好了. 而这篇文章就来谈谈第一步

rest_framework-02-权限-内置权限源码流程

权限 问题:不同视图不同权限可以访问 1.models.py from django.db import models class UserInfo(models.Model): user_type_choices = ( (1,'普通用户'), (2,'VIP'), (3,'SVIP'), ) user_type = models.IntegerField(choices=user_type_choices) # username = models.CharField(max_length=3

01 flask源码剖析之werkzurg 了解wsgi

目录 01 werkzurg了解wsgi 1. wsgi 2. flask之werkzurg源码流程 3. 总结 01 werkzurg了解wsgi 1. wsgi django和flask内部都没有实现socket,而是wsgi实现. wsgi是web服务网关接口,他是一个协议,实现它的协议的有:wsgiref/werkzurg/uwsgi django之前 from wsgiref.simple_server import make_server def run(environ, start

onLayout源码 流程 思路详解(ANDROID自定义视图)

简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量--onMeasure():决定View的大小 2.布局--onLayout():决定View在ViewGroup中的位置 3.绘制--onDraw():如何绘制这个View. 而第3步的onDraw系统已经封装的很好了,基本不用我们来操心,只需要专注到1,2两个步骤就中好了. 第一步的测量,可以参考我之前的文章:(ANDROID自定义视图--onMeasure流程,MeasureSpec详解) 而这篇文章就来谈谈第二步:"

开源一个常用的小软件的源码——系统数据库服务管理软件

郝喜路  2014年7月27日22:28:34 GitHub地址:https://github.com/haoxilu/ServiceManager    希望编程爱好者 更改添加...   开发环境:Visual Studio 2012   .Net Framework 4.0 大家在软件开发过程中,是离不开 数据库的,不管你用什么数据库,都会在系统服务上注册一个,当你安装了太多的数据库,是否有感到极大的拖掉了开机时间,影响了计算机的性能.(仅限windows系统).这时有的朋友可能会想到手动

linux系统中的11选5源码搭建相关命令行

linux目录结构(1)返回上级目录:cd .. 进入你的home目录:cd ~ 使用pwd获取当前路径:pwd (2)linux文件中11选5源码搭建基本操作:企 娥:217 1793 408①新建空白文件eg:touch test 前提是切换到自己的目录下面 ②新建目录:mkdir mydir ③使用cp命令复制一个文件到指定目录:cp test father/son/grandson,复制目录也需要加上-r或者-R ④删除文件eg:rm test,若想删除一些只有读的权限文件,rm会报错,