系列索引
本系列文章基于 OkHttp3.14
OkHttp3.14 源码剖析系列(一)——请求的发起及拦截器机制概述
OkHttp3.14 源码剖析系列(二)——拦截器大体流程分析
OkHttp3.14 源码剖析系列(六)——连接复用机制及连接的建立
OkHttp3.14 源码剖析系列(七)——请求的发起及响应的读取
路由选择
当我们第一次尝试从连接池获取连接获取不到时,若检查发现路由选择器中没有可供选择的路由,首先会进行一次路由选择的过程,因为 HTTP 请求的过程中,需要先找到一个可用的路由,再根据代理协议规则与目标建立 TCP 连接。
Route
我们先了解一下 OkHttp 中的 Route
类:
public final class Route {
final Address address;
final Proxy proxy;
final InetSocketAddress inetSocketAddress;
// ...
}
它是一个用于描述一条路由的类,主要通过了代理服务器信息 proxy
、连接目标地址 InetSocketAddress
来描述一条路由。由于代理协议不同,这里 InetSocketAddress
会有不同的含义:
- 没有代理的情况下它包含的信息是经过了 DNS 解析的 IP 以及协议的端口号
- SOCKS 代理的情况下,它包含了 HTTP 服务器的域名和协议端口号
- HTTP 代理的情况下,它包含了代理服务器经过了 DNS 解析的 IP 地址及端口号
Proxy
接着我们了解一下 Proxy
类,它是由 Java 原生提供的:
public class Proxy {
public enum Type {
// 表示不使用代理
DIRECT,
// HTTP代理
HTTP,
// SOCKS代理
SOCKS
};
private Type type;
private SocketAddress sa;
// ...
}
它是一个用于描述代理服务器的类,主要包含了代理协议的类型以及代理服务器对应的 SocketAddress
类,有以下三种类型:
DIRECT
:不使用代理HTTP
:HTTP 代理SOCKS
:SOCKS 代理
RouteSelector
在代码中是通过 RouteSelector.next
方法进行的路由选择的过程,RouteSelecter
是一个负责负责管理路由信息,并辅助选择路由的类。它主要有三个职责:
- 收集可用的路由
- 选择可用的路由
- 维护连接失败路由信息
下面我们对它的三个职责的实现分别进行介绍。
代理的收集
代理的收集过程在 RouteSelector
的构造函数中实现,RouteSelector
在创建 ExchangeFinder
时创建:
RouteSelector(Address address, RouteDatabase routeDatabase, Call call,
EventListener eventListener) {
this.address = address;
this.routeDatabase = routeDatabase;
this.call = call;
this.eventListener = eventListener;
resetNextProxy(address.url(), address.proxy());
}
让我们看到 resetNextProxy
方法:
/**
* Prepares the proxy servers to try.
*/
private void resetNextProxy(HttpUrl url, Proxy proxy) {
if (proxy != null) {
// 若用户有设定代理,使用用户设置的代理
proxies = Collections.singletonList(proxy);
} else {
// 借助ProxySelector获取代理列表
List<Proxy> proxiesOrNull = address.