bottle学习的不是很多,用bottle实现了一个链接mongodb的server。
索性bottle的源码也不是很多(4000行,主要的代码部分)。
所以我就去读了一下源码:
from bottle import Bottle, run
from bottle.ext.mongo import MongoPlugin
app = Bottle()
plugin = MongoPlugin(uri='127.0.0.1', db='collection', json_mongo=True)
app.install(plugin)
@app.route('/', method='GET')
def main(mongodb):
return "hello, world"
# 正式启动服务器,在8080端口
run(app, host=SERVER_HOST , post=SERVER_PORT)
先简化一下,分析上面几行的过程
补丁的安装
bottle支持各种补丁,可以自己定制一个,然后安装进去就可以了。
app = Bottle()
plugin = MongoPlugin(uri='127.0.0.1', db='collection', json_mongo=True)
app.install(plugin)
主要是上面这几行。
我们重点看一下install方法里面的情况。
各种牛b的代码,主要是
self.plugins.append(plugin)
这一行,把补丁加入到Bottle这个类的补丁plugins集合中。
具体什么时候运行的等下面再讲。
@app.route
这是个明显的decorator
对应Bottle类里面的def route:方法:
def decorator(callback):
if isinstance(callback, basestring): callback = load(callback)
for rule in makelist(path) or yieldroutes(callback):
for verb in makelist(method):
verb = verb.upper()
route = Route(self, rule, verb, callback, name=name,
plugins=plugins, skiplist=skiplist, **config)
self.add_route(route)
return callback
return decorator(callback)
其实里面的东西并不是很多
由于我们只是执行
@app.route(‘/’, method=’GET’)
所以,其实就是执行下面代码一次。
route = Route(self, rule, verb, callback, name=name,
plugins=plugins, skiplist=skiplist, **config)
self.add_route(route)
里面的verb就是‘GET’, rule就是‘/’, callback就是被修饰的main函数。创建好route之后就会被 调用 add_route(route)
def add_route(self, route):
self.routes.append(route)
self.router.add(route.rule, route.method, route, name=route.name)
self.routes.append(route)这个没什么好说。
self.router.add东西有点多,当然因为我们就是一个静态的路径(非正则的路径),所以其实就是
if is_static and not self.strict_order:
self.static.setdefault(method, {})
self.static[method][self.build(rule)] = (target, None)
return
如果是非静态的话,会解析然后调用
def _compile(self, method)加入到
self.dyna_regexes[method]这个里面。
run!!!
各种组装好之后就开始run了。
run的话,额,大概就是指定个server(默认为里面的WSGIRefServer),然后把app放在上面run,然后app会被调用call方法
然后调用wsgi方法
wsgi中有这么一行
out = self._cast(self._handle(environ))
先调用_handle
_handle里面
route, args = self.router.match(environ)
return route.call(**args)
调用 match里面就会调用
静态为例(里面的路径和方法我们在@app.route方法中已经填写过了)
if method in self.static and path in self.static[method]:
target, getargs = self.static[method][path]
return target, getargs(path) if getargs else {}
动态的也类似,然后就是各种给参数,
然后route.call(**args)
运行一下。
这个call会调用_make_callback方法,此方法预先执行各个补丁的apply方法,比如我的那个MongoPlugin补丁,就会被执行,然后把预先为这个方法传入参数比如传入个mongodb的连接。
main(mongodb = concrete_mongodb)
通过@cached_property的封装,保证每个方法包装一次。
然后就可以愉快的调用call了得到结果了。