深入Application¶
回想一下上节关注的WSGIApplication和DjangoApplication,都有一个共同的父类Application,并且都调用了run()方法。
关注内部¶
Application的代码不长,下面来看看整个情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | import errno
import os
import sys
import traceback
from gunicorn.glogging import Logger
from gunicorn import util
from gunicorn.arbiter import Arbiter
from gunicorn.config import Config
from gunicorn import debug
class Application(object):
"""\
An application interface for configuring and loading
the various necessities for any given web framework.
"""
def __init__(self, usage=None):
self.usage = usage
self.cfg = None
self.callable = None
self.logger = None
self.do_load_config()
def do_load_config(self):
try:
self.load_config()
except Exception, e:
sys.stderr.write("\nError: %s\n" % str(e))
sys.stderr.flush()
sys.exit(1)
def load_config(self):
# init configuration
self.cfg = Config(self.usage)
# parse console args
parser = self.cfg.parser()
opts, args = parser.parse_args()
# optional settings from apps
cfg = self.init(parser, opts, args)
# Load up the any app specific configuration
if cfg and cfg is not None:
for k, v in cfg.items():
self.cfg.set(k.lower(), v)
# Load up the config file if its found.
if opts.config and os.path.exists(opts.config):
cfg = {
"__builtins__": __builtins__,
"__name__": "__config__",
"__file__": opts.config,
"__doc__": None,
"__package__": None
}
try:
execfile(opts.config, cfg, cfg)
except Exception:
print "Failed to read config file: %s" % opts.config
traceback.print_exc()
sys.exit(1)
for k, v in cfg.items():
# Ignore unknown names
if k not in self.cfg.settings:
continue
try:
self.cfg.set(k.lower(), v)
except:
sys.stderr.write("Invalid value for %s: %s\n\n" % (k, v))
raise
# Lastly, update the configuration with any command line
# settings.
for k, v in opts.__dict__.items():
if v is None:
continue
self.cfg.set(k.lower(), v)
def init(self, parser, opts, args):
raise NotImplementedError
def load(self):
raise NotImplementedError
def reload(self):
self.do_load_config()
if self.cfg.spew:
debug.spew()
def wsgi(self):
if self.callable is None:
self.callable = self.load()
return self.callable
def run(self):
if self.cfg.spew:
debug.spew()
if self.cfg.daemon:
util.daemonize()
else:
try:
os.setpgrp()
except OSError, e:
if e[0] != errno.EPERM:
raise
try:
Arbiter(self).run()
except RuntimeError, e:
sys.stderr.write("\nError: %s\n\n" % e)
sys.stderr.flush()
sys.exit(1)
|
注意其中几个地方:
- init()和load()的定义方式
- run()的核心内容
从WSGIApplication与DjangoApplication继承自Application,并且从init()和load()的定义看,这里采用了一个最常见的设计模式: Template Method:
在父类一级定义好一系列的方法,作为算法的骨架结构,由不同的子类来实现不同的具体功能。
落实在Application中,我们可以看到算法的骨架结构就在__init__()和run()中,由它们来调用init()和load()两个空的方法,一旦有具体实例WSGIApplication和DjangoApplication中有实现,就调用具体实例的init()和load()。