Flask源码分析一:服务启动
前言
Flask是目前为止我最喜欢的一个Python Web框架了,为了更好的掌握其内部实现机制,这两天准备学习下Flask的源码,将由浅入深跟大家分享下,其中Flask版本为1.1.1。
Flask系列文章:
正文
本文将结合源码跟踪看下Flask是如何启动并运行一个服务的。在0.11版本以后,支持命令行启动flask。
目前共有两种方式可以载入应用:
1. python app.py
首先,继续贴上最简单的应用app.py:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
    return 'Hello Flask!'
if __name__ == '__main__':
    app.run()
执行python app.py即可启动。
我们看到,这段代码先初始化了Flask类并被app所指向,然后执行run()来启动程序的。
查看run方法:
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
        if os.environ.get("FLASK_RUN_FROM_CLI") == "true":
            from .debughelpers import explain_ignored_app_run
            explain_ignored_app_run()
            return
        if get_load_dotenv(load_dotenv):
            cli.load_dotenv()
            # if set, let env vars override previous values
            if "FLASK_ENV" in os.environ:
                self.env = get_env()
                self.debug = get_debug_flag()
            elif "FLASK_DEBUG" in os.environ:
                self.debug = get_debug_flag()
        # debug passed to method overrides all other sources
        if debug is not None:
            self.debug = bool(debug)
        _host = "127.0.0.1"
        _port = 5000
        server_name = self.config.get("SERVER_NAME")
        sn_host, sn_port = None, None
        if server_name:
            sn_host, _, sn_port = server_name.partition(":")
        host = host or sn_host or _host
        # pick the first value that's not None (0 is allowed)
        port = int(next((p for p in (port, sn_port) if p is not None), _port))
        options.setdefault("use_reloader", self.debug)
        options.setdefault("use_debugger", self.debug)
        options.setdefault("threaded", True)
        cli.show_server_banner(self.env, self.debug, self.name, False)
        from werkzeug.serving import run_simple
        try:
            run_simple(host, port, self, **options)
        finally:
            # reset the first request information if the development server
            # reset normally.  This makes it possible to restart the server
            # without reloader and that stuff from an interactive shell.
            self._got_first_request = False
首先入参:
| 参数 | 说明 | 
|---|---|
| host | 服务器地址,不设置的话默认为127.0.0.1 | 
| port | 端口,不设置的话默认为5000 | 
| debug | 是否为调试模式, 默认为否 | 
| load_dotenv | 从项目根目录下的.flaskenv或.env文件中导入环境变量 | 
该方法的处理流程是:对入参进行配置处理之后,执行werkzeug的run_simple()方法,
run_simple将启动一个WSGI服务。
关于WSGI协议:
- 它是关于HTTP服务器和Web应用的桥梁,定义了标准接口以提升Web应用之间的可移植性,是一套接口交互规范。
 - 它的功能是监听指定端口服务,将来自HTTP服务器的请求解析为WSGI格式,调用Flask app处理请求。
 
run_simple中的inner方法是核心,inner调用make_server().serve_forever()启动服务。关于make_server:
def make_server(host=None, port=None, app=None, threaded=False, processes=1,
                request_handler=None, passthrough_errors=False,
                ssl_context=None, fd=None):
    if threaded and processes > 1:
        raise ValueError("cannot have a multithreaded and "
                         "multi process server.")
    elif threaded:
        return ThreadedWSGIServer(host, port, app, request_handler,
                                  passthrough_errors, ssl_context, fd=fd)
    elif processes > 1:
        return ForkingWSGIServer(host, port, app, processes, request_handler,
                                 passthrough_errors, ssl_context, fd=fd)
    else:
        return BaseWSGIServer(host, port, app, request_handler,
                              passthrough_errors, ssl_context, fd=fd)
make_server会根据线程或者进程数返回相应的WSGI服务器,默认情况下返回BaseWSGIServer,ThreadedWSGIServer和ForkingWSGIServer均集成了BaserWSGIServer,接下来我们看下serve_forever()方法:
def serve_forever(self):
    self.shutdown_signal = False
    try:
        HTTPServer.serve_forever(self)
    except KeyboardInterrupt:
        pass
    finally:
        self.server_close()
最终调用了Python标准类库接口HTTPServer的serve_forever()方法,而HTTPServer又是socketserver.TCPServer的子类,通过server_bind来监听服务:
class HTTPServer(socketserver.TCPServer):
    allow_reuse_address = 1    # Seems to make sense in testing environment
    def server_bind(self):
        """Override server_bind to store the server name."""
        socketserver.TCPServer.server_bind(self)
        host, port = self.server_address[:2]
        self.server_name = socket.getfqdn(host)
        self.server_port = port
2. Flask命令
接下来我们通过flask命令来启动一个应用,hello.py:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
    return 'Hello Flask!'
Unix Bash ( Linux 、Mac 及其他):
$ export FLASK_APP=hello
$ flask run
这样便启动了该 应用,那么内部的实现机理是怎样的呢?
- 设置环境变量Flask_APP,指定应用的路径
 - 通过run命令来启动开发服务器,其中flask命令是由Flask安装的。
 
以上,就是Flask服务启动的流程。
Flask源码分析一:服务启动的更多相关文章
- Netty源码分析之服务启动
		
本节主要分析server的启动过程. Netty是基于Nio实现的,所以也离不开selector.serverSocketChannel.socketChannel和selectKey等,只不过Net ...
 - Flask源码分析二:路由内部实现原理
		
前言 Flask是目前为止我最喜欢的一个Python Web框架了,为了更好的掌握其内部实现机制,这两天准备学习下Flask的源码,将由浅入深跟大家分享下,其中Flask版本为1.1.1. 上次了解了 ...
 - zookeeper源码分析之五服务端(集群leader)处理请求流程
		
leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...
 - zookeeper源码分析之四服务端(单机)处理请求流程
		
上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...
 - flask源码分析
		
本flask源码分析不间断更新 而且我分析的源码全是我个人觉得是很beautiful的 1 flask-login 1.1 flask.ext.login.login_required(func),下 ...
 - Tomcat源码分析之—具体启动流程分析
		
从Tomcat启动调用栈可知,Bootstrap类的main方法为整个Tomcat的入口,在init初始化Bootstrap类的时候为设置Catalina的工作路径也就是Catalina_HOME信息 ...
 - JVM源码分析之JVM启动流程
		
原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 “365篇原创计划”第十四篇. 今天呢!灯塔君跟大家讲: JVM源码分析之JVM启动流程 前言: 执行Java类的main方法,程序就能运 ...
 - 源码分析Dubbo服务消费端启动流程
		
通过前面文章详解,我们知道Dubbo服务消费者标签dubbo:reference最终会在Spring容器中创建一个对应的ReferenceBean实例,而ReferenceBean实现了Spring生 ...
 - [Abp vNext 源码分析] - 1. 框架启动流程分析
		
一.简要说明 本篇文章主要剖析与讲解 Abp vNext 在 Web API 项目下的启动流程,让大家了解整个 Abp vNext 框架是如何运作的.总的来说 ,Abp vNext 比起 ABP 框架 ...
 - 4. 源码分析---SOFARPC服务端暴露
		
服务端的示例 我们首先贴上我们的服务端的示例: public static void main(String[] args) { ServerConfig serverConfig = new Ser ...
 
随机推荐
- Spotlight on Oracle注册码破解(亲测可用)
			
了解到该工具监控十分强大,该工具优点: 我就是为了监控一个Oracle数据库,查阅各种资料,真是费了十牛二虎之力,才破解完成.#_# 在客户端安装好了,连接监控的服务器,提示得要注册码,这外国的软件基 ...
 - laravel中利用循环实现隔行换色
			
1.首先在你的路由文件定义好访问的路径 2. <!doctype html><html lang="en"><head> <meta ch ...
 - 树、图、堆、STL(来自菜鸡的"炒鸡"干粮)
			
树.图.堆.STL 图论基础 简单图: 没有自环,两个顶点之间最多只有一条边. 完全图: 一个简单图,每两个顶点之间都有一条边.一共有(n-1)*n/2条边. 二分图: 一个简单图,设G=(V,E)是 ...
 - AppScan工具介绍与安装
			
本文仅供个人参考学习,如做商业用途,请购买正版,谢谢! 介绍 AppScan是IBM公司出的一款Web应用安全测试工具,采用黑盒测试的方式,可以扫描常见的web应用安全漏洞.其工作原理,首先是根据起始 ...
 - 【linux】【jenkins】自动化运维五 整合邮件提醒
			
1.安装插件 Email Extension Template Plugin 安装教程参考:https://www.cnblogs.com/jxd283465/p/11542680.html 2.系统 ...
 - kafka删除弃用的groupid
			
登录zookeeper客户端 cd zookeeper-3.4.10 sh zkCli.sh 查看groupid信息 [zk:localhost:2181(CONNECTED) 1] ls /cons ...
 - centos 升级
			
yum -y update升级所有包同时也升级软件和系统内核 yum -y upgrade只升级所有包,不升级软件和系统内核
 - GIT 安装和配置
			
Git(读音为/gɪt/.)是一个开源的分布式版本控制系统,可以有效.高速地处理从很小到非常大的项目版本管理. 一.安装 具体参照 安装 Git ,安装完git之后可以安装客户端工具 tortoise ...
 - 物料导出FreeMaker模板定义
			
<?xml version="1.0"?><?mso-application progid="Excel.Sheet"?><Wor ...
 - S2-052 漏洞复现
			
Structs2框架已知的漏洞编号如下: S2-005 S2-009 S2-016 (含S2-013) S2-019 S2-020 S2-021 S2-032 S2-037(含S2-033) DevM ...