2. OkHttp 초기 화
https://github.com/mirsfang/ExamplesOfDesignPatterns
이제 본론 으로 들 어가 보도 록 하 겠 습 니 다.
OkHttpClient 초기 화
OkHttpClient 는 코드 에서 이 렇 습 니 다.
OkHttpClient okHttpClient=new OkHttpClient.Builder().build();
OkHttpClient 는 Call 의 공장 으로 http 요청 을 보 내 고 그의 응답 을 읽 을 수 있 습 니 다. 보통 OkHttpClient 는 공식 적 으로 그의 공통성 을 제안 합 니 다. 개인 적 으로 는 전체 App 이나 client 가 하나 밖 에 없다 는 것 을 이해 합 니 다. 그렇지 않 으 면 모든 client 는 자신의 연결 풀 과 스 레 드 풀 을 가지 고 있 습 니 다. 모든 client 는 연결 풀 과 스 레 드 풀 을 만 드 는 것 입 니 다. 이런 자원 들 은 낭 비 될 것 입 니 다.
우 리 는 위의 코드 를 따라 OkHttpClient 를 분석 했다.
OkHttpClient 는 Builder 의 build 를 통 해 프레임 을 만 드 는 OkHttpClient 이기 때문에 Builder 류 와 Builder 의 build 방법 을 먼저 봅 니 다.
우선 Builder 의 build 방법:
public OkHttpClient build() {
return new OkHttpClient(this);
}
어색 합 니 다. Builder 의 구축 방법 을 살 펴 보 겠 습 니 다.
public Builder() {
dispatcher = new Dispatcher();// 。
protocols = DEFAULT_PROTOCOLS; // , http1.1 http2
connectionSpecs = DEFAULT_CONNECTION_SPECS;// (HTTPS TSL )
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();//
cookieJar = CookieJar.NO_COOKIES;//cookie
socketFactory = SocketFactory.getDefault();//sokcet
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();//
dns = Dns.SYSTEM; //Dns
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
위 에서 볼 수 있 듯 이 Builder 는 주로 기본 적 인 파 라 메 터 를 구축 한 것 입 니 다. 위 에 비교적 중요 한 파 라 메 터 를 주석 하 였 습 니 다. OkHttpClient 의 구조 함 수 를 살 펴 보 겠 습 니 다.
OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSpecs = builder.connectionSpecs;
this.interceptors = Util.immutableList(builder.interceptors);
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
this.eventListenerFactory = builder.eventListenerFactory;
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
boolean isTLS = false;
for (ConnectionSpec spec : connectionSpecs) {
isTLS = isTLS || spec.isTls();
}
if (builder.sslSocketFactory != null || !isTLS) {
this.sslSocketFactory = builder.sslSocketFactory;
this.certificateChainCleaner = builder.certificateChainCleaner;
} else {
//
X509TrustManager trustManager = systemDefaultTrustManager();
this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
}
this.hostnameVerifier = builder.hostnameVerifier;
this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
certificateChainCleaner);
this.proxyAuthenticator = builder.proxyAuthenticator;
this.authenticator = builder.authenticator;
this.connectionPool = builder.connectionPool;
this.dns = builder.dns;
this.followSslRedirects = builder.followSslRedirects;
this.followRedirects = builder.followRedirects;
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
this.pingInterval = builder.pingInterval;
}
위 에서 보면 기본적으로 전체 OkHttpClient 의 값 은 모두 Builder 에서 이 루어 진 것 이 고 구체 적 인 매개 변수 등 이 사 용 될 때 다시 이야기 합 니 다.
Request 요청 초기 화 과정
Request 빌 드 와 OkHttpClient 빌 드 의 기본 차 이 는 많 지 않 지만, Url 이 비어 있 지 않 으 면 IllegalState Exception 의 이상 을 던 집 니 다.
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
같은 방식 으로 Builder 의 구축 함 수 를 봅 니 다.
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
기본 값 은 get 요청 입 니 다. Headrs 를 초기 화 하 는 것 도 builder 형식 으로 초기 길이 가 20 인 List 입 니 다.Builder 의 선택 가능 한 매개 변 수 는 다음 과 같 습 니 다.
HttpUrl url; //url
String method; //
Headers.Builder headers;//header
RequestBody body;//
Object tag;//tag
조금 만 봐 도 큰 문제 가 없습니다. 모두 가 가 져 야 할 것 을 요구 하 는 것 입 니 다. 그러나 이 tag 는 무엇 을 하 는 것 입 니까? 그의 방법 설명 을 보 세 요.
/**
* Attaches {@code tag} to the request. It can be used later to cancel the request. If the tag
* is unspecified or null, the request is canceled by using the request itself as the tag.
*
* {@code tag} 。 。 , 。
*
*/
public Builder tag(Object tag) {
this.tag = tag;
return this;
}
로 고 를 설정 하 는 것 입 니 다. 이 로 고 를 사용 하여 요청 을 취소 할 수 있 습 니 다. 지정 하지 않 아 도 괜 찮 습 니 다. 비어 있 으 면 자체 Reques 를 사용 하 십시오. 관련 코드 는 여기에 있 습 니 다.
Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tag = builder.tag != null ? builder.tag : this;//
}
method
builder 에 다양한 요청 방법 (get post head delete 등) 이 있 습 니 다. 코드 를 보 니 Request. Builder 를 호출 한 method 방법 은 다음 과 같 습 니 다.
public Builder head() {
return method("HEAD", null);
}
public Builder post(RequestBody body) {
return method("POST", body);
}
public Builder delete(RequestBody body) {
return method("DELETE", body);
}
public Builder delete() {
return delete(Util.EMPTY_REQUEST);
}
public Builder put(RequestBody body) {
return method("PUT", body);
}
public Builder patch(RequestBody body) {
return method("PATCH", body);
}
실현 방법 은 다음 과 같다.
public Builder method(String method, RequestBody body) {
if (method == null) throw new NullPointerException("method == null");
if (method.length() == 0) throw new IllegalArgumentException("method.length() == 0");
if (body != null && !HttpMethod.permitsRequestBody(method)) {
throw new IllegalArgumentException("method " + method + " must not have a request body.");
}
if (body == null && HttpMethod.requiresRequestBody(method)) {
throw new IllegalArgumentException("method " + method + " must have a request body.");
}
this.method = method;
this.body = body;
return this;
}
여러 가지 요청 에 따 른 규칙 적 판단 을 판단 한 것 이기 도 합 니 다.
head
일반적인 요청 에서 header 도 자주 사용 되 며, okhttp 에서 header 의 구축 도 request 에서 관련 된 방법 입 니 다.
Builder header(String name, String value)
Builder addHeader(String name, String value)
Builder removeHeader(String name)
Builder headers(Headers headers)
근원 을 추적 하 는 것 은 모두 Headers. Builder headers 이다.의 조작, 그 는 위의 것 과 마찬가지 로 모두 Builder 를 통 해 구 조 를 만 들 었 기 때문에 우 리 는 먼저 그의 Builder 를 직접 보 았 다.
public static final class Builder {
final List namesAndValues = new ArrayList<>(20);
/**
* Add a header line without any validation. Only appropriate for headers from the remote peer
* or cache.
* 。 。
*/
Builder addLenient(String line) {
int index = line.indexOf(":", 1);
if (index != -1) {
return addLenient(line.substring(0, index), line.substring(index + 1));
} else if (line.startsWith(":")) {
// Work around empty header names and header names that start with a
// colon (created by old broken SPDY versions of the response cache).
return addLenient("", line.substring(1)); // Empty header name.
} else {
return addLenient("", line); // No header name.
}
}
/**
* Add an header line containing a field name, a literal colon, and a value.
* , 。
*/
public Builder add(String line) {
int index = line.indexOf(":");
if (index == -1) {
throw new IllegalArgumentException("Unexpected header: " + line);
}
return add(line.substring(0, index).trim(), line.substring(index + 1));
}
/** Add a field with the specified value.
*
*/
public Builder add(String name, String value) {
checkNameAndValue(name, value);
return addLenient(name, value);
}
/**
* Add a field with the specified value without any validation. Only appropriate for headers
* from the remote peer or cache.
*
* , 。 。
*/
Builder addLenient(String name, String value) {
namesAndValues.add(name);
namesAndValues.add(value.trim());
return this;
}
public Builder removeAll(String name) {
for (int i = 0; i < namesAndValues.size(); i += 2) {
if (name.equalsIgnoreCase(namesAndValues.get(i))) {
namesAndValues.remove(i); // name
namesAndValues.remove(i); // value
i -= 2;
}
}
return this;
}
/**
* Set a field with the specified value. If the field is not found, it is added. If the field
* is found, the existing values are replaced.
* 。 , 。 , 。
*/
public Builder set(String name, String value) {
checkNameAndValue(name, value);
removeAll(name);
addLenient(name, value);
return this;
}
private void checkNameAndValue(String name, String value) {
if (name == null) throw new NullPointerException("name == null");
if (name.isEmpty()) throw new IllegalArgumentException("name is empty");
for (int i = 0, length = name.length(); i < length; i++) {
char c = name.charAt(i);
if (c <= '\u0020' || c >= '\u007f') {
throw new IllegalArgumentException(Util.format(
"Unexpected char %#04x at %d in header name: %s", (int) c, i, name));
}
}
if (value == null) throw new NullPointerException("value == null");
for (int i = 0, length = value.length(); i < length; i++) {
char c = value.charAt(i);
if ((c <= '\u001f' && c != '\t') || c >= '\u007f') {
throw new IllegalArgumentException(Util.format(
"Unexpected char %#04x at %d in %s value: %s", (int) c, i, name, value));
}
}
}
/** Equivalent to {@code build().get(name)}, but potentially faster. */
public String get(String name) {
for (int i = namesAndValues.size() - 2; i >= 0; i -= 2) {
if (name.equalsIgnoreCase(namesAndValues.get(i))) {
return namesAndValues.get(i + 1);
}
}
return null;
}
public Headers build() {
return new Headers(this);
}
}
설명 을 통 해 우 리 는 Builder 가 올 바른 동작 을 하 는 일부 행위 의 패 키 징 을 볼 수 있 습 니 다. 이 어 Headers 안에 전체 변수
private final String[] namesAndValues;
만 있 습 니 다. 우 리 는 우리 가 자주 사용 하 는 public static Headers of(Map headers)
방법 으로 볼 수 있 습 니 다. public static Headers of(Map headers) {
if (headers == null) throw new NullPointerException("headers == null");
// Make a defensive copy and clean it up.
// 。
String[] namesAndValues = new String[headers.size() * 2];
int i = 0;
for (Map.Entry header : headers.entrySet()) {
if (header.getKey() == null || header.getValue() == null) {
throw new IllegalArgumentException("Headers cannot be null");
}
String name = header.getKey().trim();
String value = header.getValue().trim();
if (name.length() == 0 || name.indexOf('\0') != -1 || value.indexOf('\0') != -1) {
throw new IllegalArgumentException("Unexpected header: " + name + ": " + value);
}
namesAndValues[i] = name;
namesAndValues[i + 1] = value;
i += 2;
}
return new Headers(namesAndValues);
}
이 안에서 다음 과 같은 몇 가지 일 을 했다.
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.0; SLCC2;
그러면 그 가 이렇게 처리 한 결 과 는 namesAndValues[0]="User-Agent"
namesAndValues[1]="Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.0; SLCC2"
return new Headers(namesAndValues);
전역 변수 namesAndValues
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.