HttpURLConnection中connect()方法是否要显示调用及openConnection()方法源码探究

来源:互联网 发布:sal软件下载 编辑:程序博客网 时间:2024/05/22 14:18

描述:此问题是小编在学习Android项目网络知识时遇到的问题及心得,
部分内容说的是Java项目中的HttpURLConnection源码及实现原理,不过本质是相同的。此博文的语言组织不是太好加上小编对博文书写格式不是很熟练,博文格式书写问题请见谅
主要说两点:
一、connect()方法到底调用不调用:
调用connect()只是建立连接,并不会向服务器传送数据,只要调用getResponseCode(),就不必要调用connect方法(调用也无妨)。
二、openConnection()方法到底是如何返回URLConnection对象的:
openConnection()在你不自己实现网络协议等网络相关抽象类和抽象接口的情况下,此方法最终调用的是sun.net.www.protocol.http.Handler类中的方法
三、android中关于网络部分底层使用的是okhttp包下的类,包全名为com.squareup.okhttp.xxx那为何打印con时却是显示com.android.okhttp.xxx
详细内存见下文:

HttpURLConnection con = (URLConnection)url.openConnection();
通过打印con的值,发现
在Android项目中显示的是com.android.okhttp.xxx(安卓底层网络部分现在已使用okhttp框架)
在Java项目中显示的是sun.net.www.protocol.xxxx(如果你不自己实现网络协议等网络相关的抽象类和抽象接口的话)

一、关于要不要显示调用connect方法的问题:
1、不需要显示调用connect方法
2、必须调用getResponseCode()方法
小编试了一下在不调用getResponseCode()方法的时候,无论是否调用connect()方法,请求都是不能成功的,调用connect()方法只是建立连接,并不会向服务器传递数据,只用调用getRespconseCode()方法时,才会向服务器传递数据(有博文说是getInputStream()才会向服务器传递数据,getResponseCode中会调用getInputStream方法)。跟着getResponseCode()源码发现里面调用了getInputStream()方法,在getInputStream()方法中会判断当前是否连接,如果没有连接,则调用connect()方法建立连接。

二、openConnection()方法到底是如何返回URLConnection对象的
在JavaWeb项目中openConnection()方法最终是调用
sun.net.www.protocol.http.Handler中的openConnection()方法

三、三、android中关于网络部分底层使用的是okhttp包下的类,包全名为com.squareup.okhttp.internal.http那为何打印con时却是显示com.android.okhttp.internal
android系统在编译时对com.squareup.xxx进行了包名替换

protected java.net.URLConnection openConnection(URL u, Proxy p) throws IOException {        return new HttpURLConnection(u, p, this);  }

终于看到new对象了吧,此处的HttpURLConnection为sun.net.www.protocol.http包下的类,继承于java.net.HttpURLConnection,即是java.net.HttpURLConnection的实现类,故可以实例化(java.net.HttpURLConnection是抽象类,不能直接实例化)

那么java.new.URL是如何关联到sun.net.www.protocol.http包下的类的呢:

查看java.net.URL源码
发现在java.net.URL的构造方法中会调用getURLStreamHandler(protocol)方法,此方法做的逻辑操作见下面这段话

在通过URL的构造方法URL(String url)创建一个URL对象时,构造方法会根据参数url中的协议符号,来创建一个与协议匹配的URLStreamHandler实例。在本例中,协议符号为“http”。URL的构造方法创建URLStreamHandler实例的流程如下。1,如果在URL缓存中已经存在这样的URLStreamHandler实例,则无需在创建新的URLStreamHandler实例。否则继续执行下一步2,如果程序已经通过URL类的静态setURLStreamHandlerFactory()方法设置了URLStreamHandlerFactory接口的具体实现类,那么就通过这个工厂类createURLStreamHandler()方法来构造一个URLStreamHandler实例。否则继续执行下一步。3,根据系统属性java.protocol.handler.pkgs来决定URLStreamHandler具体子类的名字,然后对其实例化。例如:java -Djava.protocol.handler.pkgs = com.abc.net.www | org.javathinker.protocols.HttpClient1-D选项是用来设置系统属性。如果这些属性中还是查找不到,那么继续执行下一步4,试图实例化位于sun.net.www.protocol包中的sun.net.www.protocol.协议名.Handler类,如果失败,抛出MalformedURLException.

这段话出自博文http://blog.csdn.net/pipisky2006/article/details/6321411

其中URLStreamHandler的实现类即为sun.net.www.protocol.http.Handler类,即最终会调用sun.net.www.protocol.http.Handler类中的openConnection方法,返回URLConnection的实例。

Android中关于网络连接部分底层已经使用okhttp框架,openConnection()方法的实现与Java项目类似,只不过okhttp自己实现了关于协议处理等抽象类的子类,所以在博文刚开始时说的在Android项目中打印con值时,显示的是xxx.okhttp.xxxx.xxx(安卓底层网络部分现在已使用okhttp框架)

三、android中关于网络部分底层使用的是okhttp包下的类,包全名为com.squareup.okhttp.internal.http那为何打印con时却是显示com.android.okhttp.internal
android在编译时对com.squareup进行了包名替换,替换为com.android.,为了保持一致,是开发者知道此包是android系统内的包
替换过程见mk文件中定义的 LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
jarjar-rules.txt内容:
rule com.squareup.** com.android.@1
rule okio.** com.android.okhttp.okio.@1
关于LOCAL_JARJAR_RULES 及rule命令 含义自行查找
sun.net.www.protocol.http.Handler源码
查看getInputStream()及openConnection()方法的源码时,费了一番周折,下面附上小编参看的源码及博文链接,希望给大家带来一点帮助,如果有不正确的地方欢迎指正,探讨
http://blog.csdn.net/pipisky2006/article/details/6321411
http://blog.csdn.net/yzpbright/article/details/51099623
http://blog.csdn.net/morningsun1990/article/details/22785585
http://blog.csdn.net/pipisky2006/article/details/6321411
sun.net.www.protocol.http.HttpURLConnection源码
sun.net.www.protocol.http.Handler源码
java.net.URL源码

1 0