Tornado AsyncHTTPClient和Configurable的解析

需求:主要研究AsyncHTTPClient整个的创建过程
注意:此代码来源Tornado源码
来自Tornado httpclient.py

class AsyncHTTPClient(Configurable):

    _instance_cache = None  # type: Dict[IOLoop, AsyncHTTPClient]

    @classmethod
    def configurable_base(cls) -> Type[Configurable]: # 默认导入基类包,实现类的存放方式:AsyncHTTPClient.__impl_class=SimpleAsyncHTTPClient
        return AsyncHTTPClient

    @classmethod
    def configurable_default(cls) -> Type[Configurable]: # 默认继承AsyncHTTPClient类,实现的新类SimpleAsyncHTTPClient
        from tornado.simple_httpclient import SimpleAsyncHTTPClient
        return SimpleAsyncHTTPClient

    @classmethod
    def _async_clients(cls) -> Dict[IOLoop, "AsyncHTTPClient"]: # 给AsyncHTTPClient属性增加_async_client_dict_AsyncHTTPClient类型为WeakKeyDictionary存放loop对象
        attr_name = "_async_client_dict_" + cls.__name__
        if not hasattr(cls, attr_name):
            setattr(cls, attr_name, weakref.WeakKeyDictionary())
        return getattr(cls, attr_name)

    def __new__(cls, force_instance: bool = False, **kwargs: Any) -> "AsyncHTTPClient":
        io_loop = IOLoop.current() # 获取事件循环
        if force_instance: # 默认是True或False则是在AsyncHTTPClient类中增加WeakKeyDictionary属性存放loop对象
            instance_cache = None
        else:
            instance_cache = cls._async_clients()
        if instance_cache is not None and io_loop in instance_cache: #如果已经存在instance_cache,直接返回loop对象
            return instance_cache[io_loop]
        instance = super(AsyncHTTPClient, cls).__new__(cls, **kwargs)  # 调用Configurable类的__new__方法
        instance._instance_cache = instance_cache
        if instance_cache is not None:
            instance_cache[instance.io_loop] = instance # WeakKeyDictionary类型,io_loop实例化对象存在key里面,value存放instance即"AsyncHTTPClient实例
        return instance

    def initialize(self, defaults: Optional[Dict[str, Any]] = None) -> None:
        # AsyncHTTPClientt类__init__的方法
        self.io_loop = IOLoop.current()
        self.defaults = dict(HTTPRequest._DEFAULTS)
        if defaults is not None:
            self.defaults.update(defaults)
        self._closed = False

    def close(self) -> None:
        if self._closed:
            return
        self._closed = True
        if self._instance_cache is not None:
            cached_val = self._instance_cache.pop(self.io_loop, None)
            if cached_val is not None and cached_val is not self:
                raise RuntimeError("inconsistent AsyncHTTPClient cache")

    def fetch(
        self,
        request: Union[str, "HTTPRequest"],
        raise_error: bool = True,
        **kwargs: Any
    ) -> "Future[HTTPResponse]":
        # 这个是发送的功能,会调用SimpleAsyncHTTPClient和HTTPRequest等其它类,后期再深入
        if self._closed:
            raise RuntimeError("fetch() called on closed AsyncHTTPClient")
        if not isinstance(request, HTTPRequest):
            request = HTTPRequest(url=request, **kwargs)
        else:
            if kwargs:
                raise ValueError(
                    "kwargs can't be used if request is an HTTPRequest object"
                )

        request.headers = httputil.HTTPHeaders(request.headers)
        request_proxy = _RequestProxy(request, self.defaults)
        future = Future()  # type: Future[HTTPResponse]

        def handle_response(response: "HTTPResponse") -> None:
            if response.error:
                if raise_error or not response._error_is_response_code:
                    future_set_exception_unless_cancelled(future, response.error)
                    return
            future_set_result_unless_cancelled(future, response)

        self.fetch_impl(cast(HTTPRequest, request_proxy), handle_response)
        return future

    def fetch_impl(
        self, request: "HTTPRequest", callback: Callable[["HTTPResponse"], None]
    ) -> None:
        # 默认是找SimpleAsyncHTTPClient,fetch_impl的方法
        raise NotImplementedError()

    @classmethod
    def configure(
        cls, impl: "Union[None, str, Type[Configurable]]", **kwargs: Any
    ) -> None:
        # 调用Configurable类的configure方法
        super(AsyncHTTPClient, cls).configure(impl, **kwargs)
来自Tornado util.py

class Configurable(object):
    __impl_class = None  # 类全局变量,存放实现类
    __impl_kwargs = None  # 类全局变量,存放实例化的参数

    def __new__(cls, *args: Any, **kwargs: Any) -> Any:
        base = cls.configurable_base() # 返回AsyncHTTPClient类的地址
        init_kwargs = {}  # 实例化类的时候,传入的参数
        if cls is base: # 判断调用的类,是不是AsyncHTTPClient类
            impl = cls.configured_class() # AsyncHTTPClient类没有实configured_class方法,则调用Configurable类下面的方法,主是要创建默认的实例方法configurable_default()
            if base.__impl_kwargs: # 判断AsyncHTTPClient类,有没有传实例化参数,有的话,则更新到init_kwargs字典里面
                init_kwargs.update(base.__impl_kwargs) #把configure函数传过来参数数据设置为init_kwargs中
        else:
            impl = cls # 如果不是AsyncHTTPClient类,则实现类设置新的类
        init_kwargs.update(kwargs) # 将实例化类的传入的参数,更新到该字典
        if impl.configurable_base() is not base: # 如果AsyncHTTPClient类的话,则实例化新类并且返回
            # The impl class is itself configurable, so recurse.
            return impl(*args, **init_kwargs)
        instance = super(Configurable, cls).__new__(impl) # 返回新类或AsyncHTTPClient类的实例
        instance.initialize(*args, **init_kwargs) # 相当于执行__init__方法
        return instance # 返回最终的实例对象

    @classmethod
    def configurable_base(cls):
        raise NotImplementedError()

    @classmethod
    def configurable_default(cls):
        raise NotImplementedError()

    def _initialize(self) -> None:
        pass

    initialize = _initialize  # type: Callable[..., None]


    @classmethod
    def configure(cls, impl, **kwargs):
        # AsyncHTTPClient.configure(‘实现类字符串’,'默认的类参')
        base = cls.configurable_base()
        if isinstance(impl, str): # 实现类,必须是字符串类型,通过动态导包的方式引入
            impl = typing.cast(Type[Configurable], import_object(impl))
        if impl is not None and not issubclass(impl, cls): #判断实现类不能为空,并且必须是AsyncHTTPClient的子类
            raise ValueError("Invalid subclass of %s" % cls)
        base.__impl_class = impl # 给AsyncHTTPClient类设置实例类
        base.__impl_kwargs = kwargs # 给AsyncHTTPClient设置默认的参数值

    @classmethod
    def configured_class(cls):
        # 给AsyncHTTPClient类实例化对象,增加实现类,默认是SimpleAsyncHTTPClient类
        base = cls.configurable_base()
        if base.__dict__.get("_Configurable__impl_class") is None:
            base.__impl_class = cls.configurable_default()
        if base.__impl_class is not None:
            return base.__impl_class
        else:
            # Should be impossible, but mypy wants an explicit check.
            raise ValueError("configured class not found")

    @classmethod
    def _save_configuration(cls):
        # 保存配置信息
        base = cls.configurable_base()
        return (base.__impl_class, base.__impl_kwargs)

    @classmethod
    def _restore_configuration(cls, saved):
        # 还原配置信息
        base = cls.configurable_base()
        base.__impl_class = saved[0]
        base.__impl_kwargs = saved[1]

 

posted @ 2020-11-25 15:39  小粉优化大师  阅读(310)  评论(0编辑  收藏  举报