Flask源碼分析(一)Flask是如何運行起來的

app.run()的執行流程

1.首先來看最簡單的一個flask應用。app是Flask類的實例,最後執行了app的run方法。python

from flask import Flask

app = Flask(__name__)

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

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

2.來看一下run方法的執行過程。能夠看到,run實際是執行了werkzeug.serving的run_simple函數(無關源碼已刪減),關鍵注意這裏是傳入了self,表明傳入了當前Flask類的實例。而後繼續查看run_simple,run_simple實際是執行了其內部定義的inner函數。flask

def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
    from werkzeug.serving import run_simple
    try:
        run_simple(host, port, self, **options)
    finally:
        self._got_first_request = False

def run_simple(
    hostname,
    port,
    application,
    use_reloader=False,
    use_debugger=False,
    use_evalex=True,
    extra_files=None,
    reloader_interval=1,
    reloader_type="auto",
    threaded=False,
    processes=1,
    request_handler=None,
    static_files=None,
    passthrough_errors=False,
    ssl_context=None,
):

    def inner():
        try:
            fd = int(os.environ["WERKZEUG_SERVER_FD"])
        except (LookupError, ValueError):
            fd = None
        srv = make_server(
            hostname,
            port,
            application,
            threaded,
            processes,
            request_handler,
            passthrough_errors,
            ssl_context,
            fd=fd,
        )
        if fd is None:
            log_startup(srv.socket)
        srv.serve_forever()

    if use_reloader:
        run_with_reloader(inner, extra_files, reloader_interval, reloader_type)
    else:
        inner()

3.inner函數調用make_server函數,注意這裏傳入的主要的4個值:hostnameportapplication(即Flask實例)request_handler(None值)。make_server函數實際是返回BaseWSGIServer的實例而後執行其內部的serve_forrever方法。這裏的BaseWSGIServer即一個本地的server程序,默認是單進程單線程的(可是使用了IO多路複用技術,後續會提到)。app

def make_server(
    host=None,
    port=None,
    app=None,
    threaded=False,
    processes=1,
    request_handler=None,
    passthrough_errors=False,
    ssl_context=None,
    fd=None,
):
    """Create a new server instance that is either threaded, or forks
    or just processes one request after another.
    """
    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
        )

4.重點來了!來看BaseWSGIServer源碼。注意,這裏涉及到多個類繼承,關係有點複雜。首先看方法的調用關係。serve_forever方法是執行的HTTPServer的serve_forever方法,而HTTPServer.serve_forever是調用自身的 _handle_request_noblock方法(這裏使用的IO多路複用技術),而_handle_request_noblock方法調用自身的process_request方法來接收請求,process_request將收到的請求交由finish_request方法處理。最終,交給RequestHandlerClass處理。socket

這裏注意傳入的三個參數:requestclient_addressselfself是BaseWSGIServer自身的實例。ide

而這個ReuqustHandlerClass是什麼?看BaseWSGIServer類__init__方法中這句代碼:HTTPServer.__init__(self, server_address, handler),就知道,ReuqustHandlerClass便是WSGIRequestHandler這個類。函數

這裏總結成一句話,就是請求到來時,會將請求傳給WSGIRequestHandler這個類,進行實例化。而相應處理請求呢?確定在WSGIRequestHandler類中的__init__方法中啊!線程

class BaseWSGIServer(HTTPServer, object):

    """Simple single-threaded, single-process WSGI server."""

    def __init__(
        self,
        host,
        port,
        app,
        handler=None,
        passthrough_errors=False,
        ssl_context=None,
        fd=None,
    ):
        if handler is None:
            handler = WSGIRequestHandler

        HTTPServer.__init__(self, server_address, handler)

        self.app = app

    def serve_forever(self):
        self.shutdown_signal = False
        try:
            HTTPServer.serve_forever(self)
        except KeyboardInterrupt:
            pass
        finally:
            self.server_close()


class HTTPServer(socketserver.TCPServer):
    pass


class TCPServer(BaseServer):
    def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
        """Constructor.  May be extended, do not override."""
        BaseServer.__init__(self, server_address, RequestHandlerClass)


class BaseServer:
    def __init__(self, server_address, RequestHandlerClass):
        """Constructor.  May be extended, do not override."""
        self.server_address = server_address
        self.RequestHandlerClass = RequestHandlerClass
        self.__is_shut_down = threading.Event()
        self.__shutdown_request = False


    def serve_forever(self, poll_interval=0.5):
        try:
            with _ServerSelector() as selector:
                selector.register(self, selectors.EVENT_READ)

                while not self.__shutdown_request:
                    ready = selector.select(poll_interval)
                    # bpo-35017: shutdown() called during select(), exit immediately.
                    if self.__shutdown_request:
                        break
                    if ready:
                        self._handle_request_noblock()

                    self.service_actions()
        finally:
            self.__shutdown_request = False
            self.__is_shut_down.set()


    def _handle_request_noblock(self):
        try:
            request, client_address = self.get_request()
        except OSError:
            return
        if self.verify_request(request, client_address):
            try:
                self.process_request(request, client_address)
            except Exception:
                self.handle_error(request, client_address)
                self.shutdown_request(request)
            except:
                self.shutdown_request(request)
                raise
        else:
            self.shutdown_request(request)


    def process_request(self, request, client_address):
        self.finish_request(request, client_address)
        self.shutdown_request(request)


    def finish_request(self, request, client_address):
        """Finish one request by instantiating RequestHandlerClass."""
        self.RequestHandlerClass(request, client_address, self)

5.接着看WSGIRequestHandler這個類的代碼,這裏又涉及到複雜的繼承關係。首先看WSGIRequestHandler的實例化方法,在其父類BaseRequestHandler中,找到了實例化方法,果真,是在實例化方法時,執行自身的handle方法,來處理請求。debug

這裏注意實例化傳入的三個參數:requestclient_addressserverserver對應上面提到的BaseWSGIServer自身的實例。code

注意,這裏有點繞,仔細看。當請求到來時,執行handle方法,而handle方法已被WSGIRequestHandler重寫,重寫後的handle方法執行BaseHTTPRequestHandler的handle方法,實際是執行handle_one_request方法,而handle_one_request又被WSGIRequestHandler重寫,重寫後的handle_one_request實際是執行自身的run_wsgi方法。因此,請求的最終處理就在這裏。server

run_wsgi方法實際是執行內部定義的execute方法,此時傳入的是self.server.app。self.server對應的是BaseWSGIServer的實例,而.app就是一開始run_simple(host, port, self, **options)傳入的self,即Flask實例。而execute方法中執行app(environ, start_response),是對象()的形式。這裏會調用Flask實例的__call__方法,又回到最開始的地方了。

因此,最終app.run()所執行的流程,都在這裏了。下一節我會繼續分享,請求的處理過程。

class WSGIRequestHandler(BaseHTTPRequestHandler, object):

    def run_wsgi(self):
        """處理request"""
        def write(data):
            pass

        def start_response(status, response_headers, exc_info=None):
            pass

        def execute(app):
            application_iter = app(environ, start_response)
            try:
                for data in application_iter:
                    write(data)
                if not headers_sent:
                    write(b"")
            finally:
                if hasattr(application_iter, "close"):
                    application_iter.close()

        try:
            execute(self.server.app)
        except Exception:
            """錯誤處理"""
            pass

    def handle(self):
        try:
            BaseHTTPRequestHandler.handle(self)
        except (_ConnectionError, socket.timeout) as e:
            self.connection_dropped(e)
        except Exception as e:
            if self.server.ssl_context is None or not is_ssl_error(e):
                raise
        if self.server.shutdown_signal:
            self.initiate_shutdown()


    def handle_one_request(self):
        self.raw_requestline = self.rfile.readline()
        if not self.raw_requestline:
            self.close_connection = 1
        elif self.parse_request():
            return self.run_wsgi()


class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
    def handle_one_request(self):
        pass

    def handle(self):
        self.close_connection = True

        self.handle_one_request()
        while not self.close_connection:
            self.handle_one_request()


class StreamRequestHandler(BaseRequestHandler):
    pass


class BaseRequestHandler:

    def __init__(self, request, client_address, server):
        self.request = request
        self.client_address = client_address
        self.server = server
        self.setup()
        try:
            self.handle()
        finally:
            self.finish()

    def handle(self):
        pass
class Flask(_PackageBoundObject):
    def __call__(self, environ, start_response):
        """The WSGI server calls the Flask application object as the
        WSGI application. This calls :meth:`wsgi_app` which can be
        wrapped to applying middleware."""
        return self.wsgi_app(environ, start_response)
相關文章
相關標籤/搜索