Bottle源码分析

server适配

Bottle的一个优势是适配很多支持WSGI的Server,主要有默认是用wsgiref,CherryPy,Gunicorn,Tornado,Eventlet和Gevent。
Bottle中定义了ServerAdapter基类,通过继承这个基类,可以适配很多的WSGI Server。通过将解析完的app对象以及相关的host,port等参数传递给ServerAdapter的子类,再通过各个Server特有的启动方式,根据指定的参数启动WSGI Server。
例如,WSGIRefefServer的实现就是这样的(直接从源码中copy过来)

class WSGIRefServer(ServerAdapter):
    def run(self, app):  # pragma: no cover
        from wsgiref.simple_server import make_server
        from wsgiref.simple_server import WSGIRequestHandler, WSGIServer
        import socket

        class FixedHandler(WSGIRequestHandler):
            def address_string(self):  # Prevent reverse DNS lookups please.
                return self.client_address[0]

            def log_request(*args, **kw):
                if not self.quiet:
                    return WSGIRequestHandler.log_request(*args, **kw)

        handler_cls = self.options.get('handler_class', FixedHandler)
        server_cls = self.options.get('server_class', WSGIServer)

        if ':' in self.host:  # Fix wsgiref for IPv6 addresses.
            if getattr(server_cls, 'address_family') == socket.AF_INET:

                class server_cls(server_cls):
                    address_family = socket.AF_INET6

        self.srv = make_server(self.host, self.port, app, server_cls,
                               handler_cls)
        self.port = self.srv.server_port  # update port actual port (0 means random)
        try:
            self.srv.serve_forever()
        except KeyboardInterrupt:
            self.srv.server_close()  # Prevent ResourceWarning: unclosed socket
            raise

Bottle中还提供了一个AutoServer,这个server会从几个默认的WSGI Server中尝试进行启动,直到第一个成功的为止。利用AutoServer的这个特性,可以很自由的在几个WSGI Server之间进行切换,而不必更改自己的代码。比如本机的环境(开发环境)可以安装WSGIRef,但是到了线上环境我们直接选择安装CherryPy,这样就能直接将WSGI Server切换到CherryPy,而且应用的代码不需要做任何改动。AutoServer的代码实现如下:

class AutoServer(ServerAdapter):
    """ Untested. """
    adapters = [WaitressServer, PasteServer, TwistedServer, CherryPyServer,
                WSGIRefServer]

    def run(self, handler):
        for sa in self.adapters:
            try:
                return sa(self.host, self.port, **self.options).run(handler)
            except ImportError:
                pass

默认app

你可能感兴趣的:(Python)