目录

tornado util configurable 实现解析

tornado util configurable 实现解析

tornado.util.Configurable,一个配置类,是工厂模式的实现,通过使用构造函数(__new__())作为工厂方法。其子类必须实现 configurable_base()、configurable_default()、initialize()。通过调用 configure() 函数去配置当基类(不是指 Configurable,而是继承至 Configurable 的类,如 tornado.ioloop.IOLoop)被实例化时使用的实现类,以及配置其实现类初始化的关键字参数。

  • 示例
1
2
3
4
5
6
from tornado import httpclient

httpclient.AsyncHTTPClient.configure
("tornado.curl_httpclient.CurlAsyncHTTPClient", max_clients=10000)

http_client = httpclient.AsyncHTTPClient()

以 tornado.httpclient.AsyncHTTPClient 为示例来开始 tornado.util.Configurable 的剖析。从 tornado 源码可知,AsyncHTTPClient 继承至 Configurable,同时 tornado.curl_httpclient.CurlAsyncHTTPClient 继承至 AsyncHTTPClient。

第二行 AsyncHTTPClient 调用 configure 去设置它的实现类及关键字参数 max_clients=10000。其源码中直接调用了父类(Configurable)的 configure() 函数。

  • tornado.httpclient.AsyncHTTPClient.configure()
1
2
3
@classmethod
def configure(cls, impl, **kwargs):
    super(AsyncHTTPClient, cls).configure(impl, **kwargs)
  • tornado.util.Configurable.configure()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@classmethod
def configure(cls, impl, **kwargs):
    # cls为AsyncHTTPClient,获取可配置层次结构的基类base(AsyncHTTPClient)
    base = cls.configurable_base()
    # 由上面的例子得:impl="tornado.curl_httpclient.CurlAsyncHTTPClient"
    if isinstance(impl, (str, unicode_type)):
        # 引入tornado.curl_httpclient.CurlAsyncHTTPClient到当前上下文环境
        impl = import_object(impl)
    if impl is not None and not issubclass(impl, cls):
        raise ValueError("Invalid subclass of %s" % cls)
    # 通过全局变量保存数据,这两个变量是初始化实例
    # (tornado.util.Configurable.__new__())时非常重要的数据
    # 值为:tornado.curl_httpclient.CurlAsyncHTTPClient
    base.__impl_class = impl 
    # 值为:{"max_clients": 10000}
    base.__impl_kwargs = kwargs 

第三行获取 AsyncHTTPClient 实例,将会调用tornado.util.Configurable.__new__()函数。

  • tornado.util.Configurable.new()
 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
def __new__(cls, *args, **kwargs):
    # cls为AsyncHTTPClient,获取可配置层次结构的基类,
    # 通常是其自身(如tornado.httpclient.AsyncHTTPClient.configurable_base())
    base = cls.configurable_base()
    init_kwargs = {}
    # 判断cls是否是基类base
    if cls is base:
        # 获取当前配置的实现类,因为之前配置过实现类,即第二行,
        # 所以得到impl为tornado.curl_httpclient.CurlAsyncHTTPClient
        impl = cls.configured_class()
        # 判断configure()函数配置的关键字参数是否为空
        if base.__impl_kwargs:
            # 更新初始化参数字典,因为之前配置过关键字参数,即第二行,
            # base.__impl_kwargs={"max_clients": 10000}
            init_kwargs.update(base.__impl_kwargs)
    else:
        # 实现类即为cls
        impl = cls
    # 更新初始化参数字典
    init_kwargs.update(kwargs)
    # 实例化cls,如示例,instance为tornado.curl_httpclient.CurlAsyncHTTPClient
    instance = super(Configurable, cls).__new__(impl)
    # 初始化实例参数
    instance.initialize(*args, **init_kwargs)
    return instance
  • tornado.util.Configurable.configured_class()
1
2
3
4
5
6
7
8
9
@classmethod
def configured_class(cls):
    # cls为AsyncHTTPClient
    base = cls.configurable_base()
    # 判断有没有调用tornado.util.Configurable.configure()函数进行配置,
    # 如果没有配置过,就调用默认设置configurable_default()
    if cls.__impl_class is None:
        base.__impl_class = cls.configurable_default()
    return base.__impl_class

tornado.util.Configurable.configured_class() 函数是选取实现类的关键,它会判断是否调用过 tornado.util.Configurable.configure() 函数去配置实现类了,然后以此选择相应的实现类。