Flask -- flask项目启动加载 源码解析

项目启动

实例化Flask对象

app = Flask(__name__)

执行__init__:

 1. 对app对象封装一些初始化的值。
 	app.static_url_path
 	app.static_folder
 	app.template_folder
       app.config = Config()
 	app.view_functions = {}  # 存放函数名与  endpoint (别名)的对应关系{'index':index}
       app.before_request_funcs = {}
       app.before_first_request_funcs = []
       app.after_request_funcs = {}
 2. 添加静态文件的路由
     self.add_url_rule(
         self.static_url_path + "/<path:filename>",
         endpoint="static",
         host=static_host,
         view_func=self.send_static_file,
         )
         
 3. 实例化了url_map的对象,以后在map对象中放 【/index/ method endpoint】
     class Flask(object):
         url_rule_class = Rule
         url_map_class = Map		
 
         def __init__(self...):
             ...
             self.url_map = self.url_map_class()
     app = Flask()
     app.view_functions
     app.url_rule_class

加载配置文件(给app的config进行赋值)

from flask import Flask
app = Flask(__name__)
app.config.from_object('xx.xx')
"""
app.config.from_object('xx.xx')
源码解析:
app.config = Config()
Config().from_object()
"""
# 源码:config.py
    def from_object(self, obj):
        if isinstance(obj, string_types):
            obj = import_string(obj)
        for key in dir(obj):
            if key.isupper():
                self[key] = getattr(obj, key)		# 执行Config()的 __getitem__
1. 读取配置文件中的所有键值对,并将键值对全都放到Config对象。(Config是一个字典)
2. 把包含所有配置文件的Config对象,赋值给 app.config
3. from_object会执行 Config()字典的__getitem__方法,去获取值

特殊的装饰器加载(中间件)

def before_request(self, f):
    self.before_request_funcs.setdefault(None, []).append(f)
    return f
# 数据结构:{None:[f1,f2]}
def before_first_request(self, f):
    self.before_first_request_funcs.append(f)
    return f
# 数据结构:[f3, f4]  会在项目启动后,第一次请求执行,后面请求不执行
def after_request(self, f):
    self.after_request_funcs.setdefault(None, []).append(f)
    return f
# 数据结构:{None:[f5,f6]}

添加路由映射

from flask import Flask

app = Flask(__name__,static_url_path='/xx')

@app.route('/index')
def index():
    return 'hello world'

源码解析:app.py

def route(self, rule, **options)
    def decorator(f):
       endpoint = options.pop("endpoint", None)
       self.add_url_rule(rule, endpoint, f, **options)
       return f

    return decorator

add_url_rule进入:

  1. 首先会将 endpoint (别名)添加到 options中,然后将methods获取到。

  2. 再执行rule = url_rule_class = Rule()将URL、methods、endpoint 封装到rule对象中;

  3. url_map.add(rule)rule对象添加到url_map=Map()对象中。

  4. self.view_functions[endpoint] = view_func,将函数名与 endpoint (别名)的对应关系添加到 view_functions中。

    def add_url_rule(
        self,
        rule,
        endpoint=None,
        view_func=None,
        provide_automatic_options=None,
        **options
    ):
        if endpoint is None:
            endpoint = _endpoint_from_view_func(view_func)
        options["endpoint"] = endpoint
        methods = options.pop("methods", None)
		# 。。。略
        
        rule = self.url_rule_class(rule, methods=methods, **options)
        rule.provide_automatic_options = provide_automatic_options

        self.url_map.add(rule)
        if view_func is not None:
            old_func = self.view_functions.get(endpoint)
            if old_func is not None and old_func != view_func:
                raise AssertionError(
                    "View function mapping is overwriting an "
                    "existing endpoint function: %s" % endpoint
                )
            self.view_functions[endpoint] = view_func
1. 将 url = /index  和  methods = [GET,POST]  和 endpoint = "index"封装到Rule对象

2. 将Rule对象添加到 app.url_map中。

3. 把endpoint和函数的对应关系放到 app.view_functions中。
  • 截止目前,app封装了三个属性

    app.config    # Config()对象,继承dict字典
    app.url_map    # 存放URL、methods、endpoint关系
    app.view_functions  # 存放函数名、endpoint关系
    

运行flask

from flask import Flask

app = Flask(__name__,static_url_path='/xx')

@app.route('/index')
def index():
    return 'hello world'

if __name__ == '__main__':
    app.run()

源码:

# run.py
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
    try:
        run_simple(host, port, self, **options)
    finally:
           
        self._got_first_request = False
1. 执行run,内部调用werkzeug的run_simple,创建socket,监听IP和端口,等待用户请求到来。

2. 一旦有用户请求,就会执行执行self(),也就是app.__call__方法。本质就是将wsgi启动起来。

	class Flask(object):
        def __call__(self,envion,start_response):
            return self.wsgi_app(environ, start_response)
        def run(self):
            run_simple(host, port, self, **options)

    if __name__ == '__main__':
        app.run()
posted @ 2019-11-23 18:39  SensorError  阅读(533)  评论(0编辑  收藏  举报