需求:主要研究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]