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]