WebScarab关键源码分析(4)

来源:互联网 发布:富士镜头推荐 知乎 编辑:程序博客网 时间:2024/05/17 03:37
在上一篇博文里我们分析了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吧。