05 | Tornado源码分析:Configurable

2020-05-28 00:01:21 浏览数 (1)

hello,各位好,好久没有更新,一直在整理Tornado 底层源码,力求用最少的代码来为大家讲解清楚其底层的运行原理。看到标题是否想到今天会分享什么呢? 先从一张图中看一下tornado 各个部件 的位置:

不知大家是否记得上次我们讲过的代码,其中一个片段是这样的: tornado.ioloop.IOLoop.instance().start() 我们今天就从这句开始分析,从图上我们也能看到 IOLoop是最底层的,这个是做什么的呢?这个是一个“大循环”,是事件循环的核心代码。单击进入我们先大概看一下长什么样子的:

从图片可以看出,这个IOLoop类是继承了 Configurable 这个类。为何要继承这个类?能为IOLoop做什么呢? 我们看一下代码:[注意:我贴出的代码是我删减过后的代码,只为给大家说清楚其主要逻辑和设计思路] 先整体看一下涉及到的主要函数内容:

代码语言:javascript复制
# -*- encoding: utf-8 -*-
# !/usr/bin/python
"""
@File    : configure_core.py
@Time    : 2020/5/23 18:10
@Author  : haishiniu
@Software: PyCharm
"""
from tornado.util import unicode_type, import_object

class Configurable(object):
    __impl_class = None  # type: type
    __impl_kwargs = None  # type: Dict[str, Any]

    def __new__(cls, *args, **kwargs):
        base = cls.configurable_base()  # 返回子类的配置基类 -->IOLoop
        init_kwargs = {}

        # 如果子类的配置基类就是子类本身,那么:
        # 如果配置基类通过__impl_class 属性指定了实现类,则使用它;
        # 否则,使用子类的 configurable_default() 方法返回的实现类。
        if cls is base:
            impl = cls.configured_class()  # 具体实现类[底层的IO多路复用机制]EPollIOLoop
            if base.__impl_kwargs:
                init_kwargs.update(base.__impl_kwargs)

        # 如果子类的配置基类不是自身,直接使用子类作为实现类。
        else:
            impl = cls
        init_kwargs.update(kwargs)

        # 创建实现类的实例
        instance = super(Configurable, cls).__new__(impl)

        # 使用传递给构造方法的参数,调用实例的initialize方法,进行初始化。
        # 实例的__init__方法也会被自动调用,但是一般不应该使用__init__方法进行初始化,而是建议使用initialize方法
        instance.initialize(*args, **init_kwargs)  # EPollIOLoop(initialize)  --> PollIOLoop(initialize)  --> IOLoop --> Configurable
        return instance

    # configurable_base() 方法用于 返回子类的配置基类。通常,子类的配置基类就是其自身(但是不是必须)。
    # issubclass(子类, 配置基类) == True。
    # 该方法需要在子类中实现。
    @classmethod
    def configurable_base(cls):
        # type: () -> Any
        raise NotImplementedError()

    # configured_class()方法的作用是:
    # 如果子类的__impl_class属性是None(也就是,其配置基类没有通过__impl_class属性指定实现类),
    # 那么,则使用它的 configurable_default() 方法返回的类作为实现类,并将其保存到配置基类的__impl_class属性中;
    # 否则,直接使用配置基类的__impl_class属性指定的实现类。
    # 实现类是子类自身或其子类。
    @classmethod
    def configured_class(cls):
        # type: () -> type
        base = cls.configurable_base()  # 返回子类的配置基类 -->IOLoop
        if cls.__impl_class is None:
            base.__impl_class = cls.configurable_default()  # 具体实现类[底层的IO多路复用机制]EPollIOLoop
        return base.__impl_class

    # configure()方法用于在 运行时,为 Configurable的子类指定实现类,以及初始化时使用的参数。
    # 它们会被保存到 子类的配置基类的 __impl_class 和 __impl_kwargs属性中
    @classmethod
    def configure(cls, impl, **kwargs):
        # type: (Any, **Any) -> None
        base = cls.configurable_base()  # 返回子类的配置基类 -->IOLoop
        if isinstance(impl, (str, unicode_type)):
            impl = import_object(impl)
        if impl is not None and not issubclass(impl, cls):
            raise ValueError("Invalid subclass of %s" % cls)

        base.__impl_class = impl
        base.__impl_kwargs = kwargs

# 简单总结:
# 继承 Configurable 的子类,需要实现下列的方法:
    # 1.configurable_base(cls):通常返回子类自身
    # 2.configurable_default(cls):返回默认的实现类,比如根据不同的操作系统平台,返回不同的实现类

# 子类的实现类,需要实现:
# initialize(self, *a, **kw):用于实例的初始化

# Configurable的核心是其构造方法:__new__。它是 其实现子类的 [工厂方法]。
# 在新式类中,如果子类没有定义__new__方法,那么会使用父类的该方法,来创建对象。
# 因此,Configurable的 未定义__new__方法的子类(比如IOLoop等) 都会使用Configurable的[构造方法]。

0 人点赞