zoukankan      html  css  js  c++  java
  • 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]
  • 相关阅读:
    使用sublimehighlight 将文本 转化html
    iOS- 制作U盘安装Mac OS X 系统
    垃圾回收的常见算法
    jvm的三种参数类型
    HashMap遍历取值
    不要在 foreach 循环里进行元素的 remove/add 操作
    Arrays.asList()使用指南
    正确使用 equals 方法
    elasticsearch安装与配置(在Linux环境下配置)
    本地访问Linux里端口连接失败
  • 原文地址:https://www.cnblogs.com/ygbh/p/14036497.html
Copyright © 2011-2022 走看看