OkHttp源码分析

本文详细介绍了OkHttp在Android和Java开发中的应用,包括资源引用、Builder构建OkHttpClient、同步和异步请求示例,以及源码中的关键组件和优点,如连接池、HTTP/2支持和拦截器机制。
摘要由CSDN通过智能技术生成

OkHttp 是一个广泛应用于 Android 和 Java 开发领域的开源网络请求框架,它以其简洁、易用和高性能的特点而闻名。本文就从简单的使用到源码分析来介绍OkHttp。

1.引用资源

dependencies {
   implementation(“com.squareup.okhttp3:okhttp:3.14.9”)
   implementation("com.squareup.okhttp3:logging-interceptor:3.14.9")
}

具体使用什么版本以自己实际情况为准
官网地址

构建一个OkHttpClient对象(Builder方式)

OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpClient client=builder.build()

发送请求

Get方式发送一个同步请求

new Thread(new Runnable() {  
    @Override  
    public void run() {  
       OkHttpClient.Builder builder = new OkHttpClient.Builder();
        OkHttpClient client=builder.build()
        Request request = new Request.Builder()  
                .url("你的url")  
                .build();  
        try (Response response = client.newCall(request).execute()) {  
            if (!response.isSuccessful()) {  
                throw new IOException("Unexpected code " + response);  
            } else {  
                // 这里处理你的响应数据,比如解析JSON  
                String responseBody = response.body().string();
                // 现在我们需要在主线程中更新UI或执行其他操作  
                runOnUiThread(new Runnable() {  
                    @Override  
                    public void run() {  
                        // 在这里更新UI或执行其他主线程任务  
                    }  
                });  
            }  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
}).start();

这里.get()可以省略不写(默认就是get请求),通过调用call.execute()来发送一个同步请求。

Get方式发送一个异步请求

OkHttpClient.Builder builder = new OkHttpClient.Builder();
 OkHttpClient client=builder.build()
Request request = new Request.Builder()  
        .url("你的url")  
        .build();    
client.newCall(request).enqueue(new Callback() {  
    @Override  
    public void onFailure(Call call, IOException e) {  
        e.printStackTrace();  
        // 请求失败的处理逻辑  
    }  
    @Override  
    public void onResponse(Call call, Response response) throws IOException {  
        if (!response.isSuccessful()) {  
            throw new IOException("Unexpected code " + response);  
        } else {  
            // 在这里处理你的响应数据,比如解析JSON  
            String responseBody = response.body().string();  
            runOnUiThread(new Runnable() {  
                @Override  
                public void run() {  
                    // 在这里更新UI或执行其他主线程任务
                }  
            });  
        }  
    }  
});

Post请求只需将get()换成post即可,

import okhttp3.*;  
  
// ...  
OkHttpClient.Builder builder = new OkHttpClient.Builder(); 
 OkHttpClient client=builder.build()
// 创建POST请求体,这里使用FormBody作为示例  
RequestBody formBody = new FormBody.Builder()  
        .add("key1", "value1")  
        .add("key2", "value2")  
        .build();   
Request request = new Request.Builder()  
        .url("http://example.com/api/post")  
        .post(formBody)  
        .build();    
client.newCall(request).enqueue(new Callback() {  
    @Override  
    public void onFailure(Call call, IOException e) {  
        e.printStackTrace();  
        // 请求失败的处理逻辑,可以更新UI显示错误信息  
        runOnUiThread(new Runnable() {  
            @Override  
            public void run() {  
                // 更新UI显示错误信息  
            }  
        });  
    }  
 
    @Override  
    public void onResponse(Call call, Response response) throws IOException {  
        if (!response.isSuccessful()) {  
            throw new IOException("Unexpected code " + response);  
        } else {  
            // 解析响应体  
            String responseBody = response.body().string();  
            // 在主线程上更新UI  
            runOnUiThread(new Runnable() {  
                @Override  
                public void run() {  
                    // 更新UI显示响应内容                 
                }  
            });  
        }  
    }  
});  

上面就是OkHttp的简单使用了。

源码分析

第一步是构建一个OkHttpClient对象。
通过Builder构建。
在这里插入图片描述
可以看到在Builder方法里主要做了一下几个工作
1.初始化dispatcher,并将其赋值给 dispatcher 属性。分发器用于调度和管理网络请求
2.protocols = DEFAULT_PROTOCOLS;:将默认的协议(DEFAULT_PROTOCOLS)赋值给 protocols 属性。默认协议通常包括 HTTP/1.1 和 HTTP/2。
3.connectionSpecs = DEFAULT_CONNECTION_SPECS;:将默认的连接规范(DEFAULT_CONNECTION_SPECS)赋值给 connectionSpecs 属性。连接规范用于配置连接的安全策略和传输协议。
4.eventListenerFactory = EventListener.factory(EventListener.NONE);:创建一个事件监听器工厂,用于生成事件监听器实例。默认情况下,事件监听器为空。
5.proxySelector = ProxySelector.getDefault();:获取系统默认的代理选择器,并将其赋值给 proxySelector 属性。如果系统默认的代理选择器为 null,则创建一个空的代理选择器(NullProxySelector)。
6.cookieJar = CookieJar.NO_COOKIES;:将一个不处理任何 Cookie 的 CookieJar 实例赋值给 cookieJar 属性。这意味着默认情况下不会处理任何 Cookie。
7.socketFactory = SocketFactory.getDefault();:获取系统默认的 Socket 工厂,并将其赋值给 socketFactory 属性。这个 Socket 工厂用于创建 Socket 连接。
8.hostnameVerifier = OkHostnameVerifier.INSTANCE;:将 OkHttp 默认的主机名验证器赋值给 hostnameVerifier 属性。这个验证器用于验证服务器证书的主机名。
9.certificatePinner = CertificatePinner.DEFAULT;:将默认的证书钉住实例赋值给 certificatePinner 属性。这个证书钉住策略用于限制客户端所信任的服务器证书。
10.proxyAuthenticator = Authenticator.NONE;:将一个空的代理认证器实例赋值给 proxyAuthenticator 属性。默认情况下不使用任何代理认证。
11.authenticator = Authenticator.NONE;:将一个空的认证器实例赋值给 authenticator 属性。默认情况下不使用任何认证器。
12.connectionPool = new ConnectionPool();:创建一个新的连接池实例,并将其赋值给 connectionPool 属性。连接池用于管理和复用 TCP 连接。
13.dns = Dns.SYSTEM;:将系统默认的 DNS 解析器赋值给 dns 属性。默认情况下使用系统默认的 DNS 解析器。
14.followSslRedirects = true;:设置是否自动遵循 SSL 重定向。
15.followRedirects = true;:设置是否自动遵循 HTTP 重定向。
16.retryOnConnectionFailure = true;:设置在连接失败时是否自动重试。
17.callTimeout = 0;:设置调用超时时间,默认为 0,即没有超时限制。
18.connectTimeout = 10_000;:设置连接超时时间为 10 秒。
19.readTimeout = 10_000;:设置读取超时时间为 10 秒。
20.writeTimeout = 10_000;:设置写入超时时间为 10 秒。
21.pingInterval = 0;:设置 ping 的间隔时间。

client.newCall
调用了RealCall下面的newRealCall返回了一个RealCall对象。
在这里插入图片描述
Transmitter 负责发送请求并接收响应。
在这里插入图片描述

同步请求

client.newCall(request).execute()
在这里插入图片描述
synchronized代码块中的代码只能被执行一次,这样可以确保在多线程环境下,不会重复执行同一个请求。

transmitter.timeoutEnter();
transmitter.callStart();

这两行代码执行了网络请求前的一些准备工作,包括开始计时超时时间和标记请求开始执行
client.dispatcher().executed(this);调用了Dispatcher的executed,把RealCall对象添加到正在执行的同步请求列表中。
在这里插入图片描述
client.dispatcher().finished(this);调用了Dispatcherl里的finished。

在这里插入图片描述

在这里插入图片描述
promoteAndExecute() 方法遍历了 readyAsyncCalls 队列去寻找能够执行的 AsynCall,若找到,会判断runningAsyncCalls的长度是否大于
最大请求书maxRequests,如果大于等于break,否则检查当前异步调用所在主机的并发请求数是否已达到最大限制 maxRequestsPerHost,如果是,则跳过该异步调用,继续处理下一个。这个检查确保不会超出每个主机的最大请求数。
如果都不满足则从readyAsyncCalls列表中移除异步调用并加到runningAsyncCalls中。
最终遍历临时的可执行队列,依次执行。
executorService()线程池没有核心线程,线程个数最大为Integer.MAX_VALUE,空闲时线程存活时间为60s。

在这里插入图片描述
最后执行client.dispatcher().finished(),再说同步请求时我们已经介绍了这个方法,上面红色框圈起来的代码又执行了promoteAndExecute,
就是说每当一个任务执行完毕后,会重新遍历readyAsyncCalls,然后 把任务依次加到runningAsyncCalls。

getResponseWithInterceptorChain
在这里插入图片描述

getResponseWithInterceptorChain是真正获取response的地方,是整个OkHttp的核心,采用了责任链模式。
通过拦截器构建了以RealInterceptorChain责任链,通过process 方法开始依次执行链上的每个节点,并返回处理后的 Response。
可以看到这个方法有五个拦截器
1.RetryAndFollowUpInterceptor(重试和重定向拦截器)
第一个接触到请求,最后接触到响应的拦截器,负责判断是否需要重新发起整个请求,负责处理和错误重试和重定向的,确保了请求的可靠性可正确定。
2.BridgeInterceptor(桥接拦截器)
补全请求,并对响应进行额外处理,主要用于在 HTTP 请求和 WebSocket 请求之间进行桥接转换。
3.CacheInterceptor(缓存拦截器)
处理缓存相关的逻辑,提高了网络请求的效率和性能,并提供了对缓存策略的灵活控制。
4.ConnectInterceptor(链接拦截器)
与服务器完成TCP连接 (Socket),内部维护一个连接池,负责连接复用、创建连接、释放连接。
5.CallServerInterceptor(请求服务拦截器)
与服务器通信,负责处理网络请求的发送和接收工作,封装请求数据与解析响应数据。

异步请求

client.newCall(request).enqueue()
调用RealCall的enqueue(记住这里传的是AsyncCall)
在这里插入图片描述
最终调用的是Dispatcher的enqueue
在这里插入图片描述
promoteAndExecute方法里最后执行executeOn
在这里插入图片描述
里面执行了executorService.execute(this);

在这里插入图片描述
execute传入Runbale,会执行他的run方法。
在这里插入图片描述
AsyncCall继承了NameRunuable
在这里插入图片描述
NameRunuable实现了Runable,run方法执行了execute(),又回到了RealCall里的execute(),具体分析上面已经介绍过了。

优点

1.简洁易用的 API:
OkHttp 提供了简洁易用的 API,使得进行网络请求变得非常方便。通过简洁的链式调用,可以轻松地构建请求、设置请求头、添加参数等操作,同时支持同步和异步请求。

2.支持 HTTP/2 和 SPDY协议:
OkHttp 支持 HTTP/2 和 SPDY,这两种协议都是现代网络通信的重要协议,能够提升网络请求的性能和效率。

3.连接池和请求复用:
OkHttp 内置了连接池和请求复用机制,可以有效地减少网络请求的延迟和资源消耗。通过连接池,可以复用已经建立的连接,避免频繁地创建和销毁连接,提高了请求的效率。

4.自动压缩和解压缩:
OkHttp 支持自动压缩和解压缩数据,可以减少网络传输的数据量,提高传输效率。

5.请求重试和超时设置:
OkHttp 提供了灵活的请求重试和超时设置机制,可以根据实际需求进行配置,保证网络请求的稳定性和可靠性。

6.拦截器机制:
OkHttp 使用拦截器机制来实现功能的扩展和定制。通过拦截器,可以灵活地添加、修改或者删除请求或响应的头信息,实现诸如日志记录、重试、缓存等功能。

7.支持 HTTPS:
OkHttp 支持 HTTPS 协议,能够通过 TLS/SSL 来确保通信的安全性,同时支持证书验证和域名校验,保护网络通信的安全。

8.高性能:
OkHttp 在性能方面表现优异,具有较低的延迟和资源消耗,能够处理大量并发请求,适用于高性能的网络通信场景。

总结

OkHttp

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值