在上一篇博文里我们分析了URLFetcher的一些行为以及相关方法,顺着这个思路走,接着我们遇到的问题是:
谁使用了URLFetcher?它是如何使用URLFetcher的?
这就又牵扯到了两个关键的类:HTTPClientFactory和FetchQueue。
首先从HTTPClientFactory说起,从名字我们也可以大概看出,这是一个工厂模式,这个工厂可以产生HTTPClient对象,当然HTTPClient是一个接口,实际上就是可以产生URLFetcher对象(该对象实现了HTTPClient接口)。
工厂本身是一个单例模式,其第一行代码说明了这一点:
private static HTTPClientFactory _instance = new HTTPClientFactory();
同时使用getinstance方法返回此唯一实例:
public static HTTPClientFactory getInstance() { return _instance; }
接着比较重要的方法有产生URLFetcher对象的方法:
public HTTPClient getHTTPClient() { URLFetcher uf = new URLFetcher(); uf.setHttpProxy(_httpProxy, _httpProxyPort); uf.setHttpsProxy(_httpsProxy, _httpsProxyPort); uf.setNoProxy(_noProxy); uf.setSSLContextManager(_sslContextManager); uf.setTimeouts(_connectTimeout, _readTimeout); uf.setAuthenticator(_authenticator); return uf; }
可以看出,该方法很简单,首先设置一些代理以及超时相关的设定,然后就直接返回新建的URLFetcher对象了。
但是让人困惑的是以下这个方法:
public Response fetchResponse(Request request) throws IOException { HTTPClient hc = null; synchronized (_availableClients) { if (_availableClients.size()>0) { hc = (HTTPClient) _availableClients.remove(0); } else { _logger.info("Creating a new Fetcher"); hc = getHTTPClient(); _clientList.add(hc); } } Response response = null; IOException ioe = null; try { response = hc.fetchResponse(request); } catch (IOException e) { ioe = e; } synchronized (_availableClients) { _availableClients.add(hc); } if (ioe != null) throw ioe; return response; }
为什么让人困惑呢,因为笔者认为这个方法出现在这里很不合理。
设计模式告诉我们作为一个Factory,它唯一的职责就在于创建用户想要的对象,也就是将类的实例化的工作解耦出来。而这个方法很明显是封装了URLFetcher的fetchResponse功能,换句话说,它起到了一个管理HTTPClient的功能,而这个功能无论如何都不是属于Factory的职责,所以说这个方法出现在这里很怪。
当然或许代码原作者本身就想让Factory起到一个管理功能,但这样假设的话public的getHttpClient方法又说不清了,因为这个方法的存在使得不会有其它的类从逻辑上会尝试去调用getHttpClient方法(为什么呢?你调用getHttpClient方法肯定是为了获取一个实现HTTPClient接口的对象,你得到这个对象肯定是为了调用fetchResponse方法,而factory已经帮你把这个方法封装好了,为啥你还要去自己调用getHttpClient呢?),反正无论怎么说这里从逻辑上设计的不合理。
当然逻辑归逻辑,面向对象方法学归面向对象方法学,虽然看上去让人不舒服,但好用就行了,不是么?
吐槽完了之后继续分析这段代码的逻辑,可以看出代码首先锁住_availableClients,这是个什么什么东西呢?按F3追上去发现是一个arraylist,从名字也可以看出,这个ArrayList存储了可用的Clients,然后尝试从这个对象里获取第一个位置(下标为0)的HttpClient对象,若容器为空,说明当前没有可用对象便实例化一个新的对象。然后用调用这个对象的fetchResponse方法去请求这个Request,最后再锁死_availableClients,把用完的Client加进去。
这段代码一开始看上去没啥难的,但为了方便理解以后的代码,需要注意这两点:
1、HttpClient是反复使用的,虽然采用资源池的方法最大限度的使用了已有资源,但是却不能很好的利用Http1.1中的connect:keep-alive属性。(为什么?因为两个指向相同地址的请求可能使用不同的httpClient,并且httpClient每次fetchResponse都要重新连接。)
2、在response返回(函数结束)之前,httpClient已经先于response返回资源池。
至此HttpClientFactory类的分析就结束了。考虑到篇幅问题,就在下篇里面分析FetcherQueue吧。