OkHttp3源碼解析(整體流程)

2021-02-17 code小生


前言

今天主要講一下OkHttp3源碼解析(整體流程),主要分為四大塊:

okhttp的基本用法

OkHttpClient分析

Request分析

Call分析 {同步請求與異步請求}

基本用法

1.集成1.1.依賴

implementation 'com.squareup.okhttp3:okhttp:3.11.0'

可以去Okhttp-Github 查看並依賴最新的版本。

1.2權限

添加網絡權限

<uses-permission android:name="android.permission.INTERNET" />

2.使用2.1 同步GET請求


OkHttpClient okHttpClient=new OkHttpClient();
final Request request=new Request.Builder()
.url("https://www.wanandroid.com/navi/json")
.get()
.build();
final Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
Log.e("同步結果---- ",response.body().string()+"");

} catch (IOException e) {

e.printStackTrace();

}

運行後發現報錯:

android.os.NetworkOnMainThreadException

在Android4.0以後,會發現,只要是寫在主線程(就是Activity)中的HTTP請求,運行時都會報錯,這是因為Android在4.0以後為了防止應用的ANR(Aplication Not Response)異常。解決方法就是在子線程中運行:


OkHttpClient okHttpClient=new OkHttpClient();
final Request request=new Request.Builder()
.url("https://www.wanandroid.com/navi/json")
.get()
.build();
final Call call = okHttpClient.newCall(request);

new Thread(new Runnable() {
@Override
public void run() {
try {
Response response = call.execute();
Log.e("同步結果---- ",response.body().string()+"");

} catch (IOException e) {

e.printStackTrace();

}
}
}).start();

2.2 異步GET請求


OkHttpClient okHttpClient=new OkHttpClient();
final Request request=new Request.Builder()
.url("https://www.wanandroid.com/navi/json")
.get()
.build();
final Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d("okhttp_error",e.getMessage());
}

@Override
public void onResponse(Call call, Response response) throws IOException {
Gson gson=new Gson();

Log.d("okhttp_success",response.body().string());
}
});

2.3 POST請求

POST請求支持提交文件,流,string,表單等等 。這裡拿POST表單請求作為請求示例:

OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("username", "qinzishuai")
.add("password", "111111")
.build();
Request request = new Request.Builder()
.url("https://www.wanandroid.com/user/login")
.post(requestBody)
.build();

okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d("okhttp", "onFailure: " + e.getMessage());
}

@Override
public void onResponse(Call call, Response response) throws IOException {

Log.d("okhttp", "onResponse: " + response.body().string());
}
});

OkHttpClient分析初始化-構造方式

創建 OkHttpClient實例的兩種方式

1. OkHttpClient okHttpClient = new OkHttpClient();

2. OkHttpClient okHttpClient = new OkHttpClient.Builder().build();

我們先研究第一種構造方式,也是默認的方式,我們點擊OkHttpClient方法進去:

public OkHttpClient() {
this(new Builder());
}

發現是一個類構造方法,this其實就是指的是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;
....部分代碼省略
}

然後順理成章的看一下new Builder() 方法

public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}

不出意料, 都是做了一些初始化配置...這塊的細節先不說,我們繼續看另一個種構造方式

2. OkHttpClient okHttpClient = new OkHttpClient.Builder().build();

我們點擊build()方法:

public OkHttpClient build() {
return new OkHttpClient(this);
}

這裡需要我們注意的是Builder 它是靜態內部類,這很關鍵!看源碼一定要仔細哦...
這下就全明白了吧?

這裡的建造者Builder這部分是用了 設計模式中的-建造者模式


如果不知道此模式的夥伴先去把它搞懂,我這裡就先簡單的說一下:
定義:建造者模式是設計模式的一種,將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。


實用範圍

當創建複雜對象的算法應該獨立於該對象的組成部分以及它們的裝配方式時。
當構造過程必須允許被構造的對象有不同表示時。

可以在網上上找找建造者模式的例子去學習一下,學習之後可以通過建造者模式去模仿okhttp的請求(Request) 就理解的充分了!

OkHttpClient初始化都配置了什麼????

上面講到了OkHttpClient的兩種構造方式, 通過查看源碼,兩種方式的配置是相同的,下面具體看一下到底配置了什麼:

public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}

Dispatcher   調度器,執行異步請求時的策略

protocols    OKHTTP實現的協議LIST

connectionSpecs   TLS版本與連接協議

eventListenerFactory    監聽器

proxySelector   代理選擇器

CookieJar   cookie

socketFactory    socket 工廠

hostnameVerifier   主機name驗證

proxyAuthenticator   代理驗證

authenticator    驗證

connectionPool    連接池

dns   dns域名

cache   緩存

interceptors   攔截器

networkInterceptors   網絡攔截器

等等等等,我就不一一列出了,這些如果開始不知道是幹什麼的,可以用谷歌翻譯去翻譯類開頭的注釋或者成員變量的名字,開始會好理解一下的。我也是這樣翻譯的。
至於每個成員變量的具體原理我們分析到它時再具體講解...

Request分析Request初始化

當我們構建完OkHttpClient對象,需要構造Request對象,構造方式如下:

1.Get請求

final Request request=new Request.Builder()
.url("https://www.wanandroid.com/navi/json")
.get()
.build();


2.POST請求

拿POST提交表單請求,這時就需要聲明一個RequestBody對象了

RequestBody requestBody = new FormBody.Builder()
.add("username", "qinzishuai")
.add("password", "123456")
.build();
Request request = new Request.Builder()
.url("https://www.wanandroid.com/user/login")
.post(requestBody)
.build()

看到上面代碼是不是很熟悉?和OkHttpClient很相似, 沒錯 Request 的構建也是Builder模式!

我們點擊Request源碼進去,果然 其中有靜態的Builder內部類:

然後我們查一下Request在初始化時配置了哪些參數???

public static class Builder {
HttpUrl url;
String method;
Headers.Builder headers;
RequestBody body;


public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}


public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
}

從代碼看到了 如果沒有聲明,默認是Get請求 this.method = "GET" ,至於url等欄位需要我們自己去配置:

HttpUrl

請求訪問的url ,可以傳String與URL 具體方法如下:

public Builder url(String url) {
if (url == null) throw new NullPointerException("url == null");


if (url.regionMatches(true, 0, "ws:", 0, 3)) {
url = "http:" + url.substring(3);
} else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
url = "https:" + url.substring(4);
}
return url(HttpUrl.get(url));
}
public Builder url(URL url) {
if (url == null) throw new NullPointerException("url == null");
return url(HttpUrl.get(url.toString()));
}

method

請求類型 String method,支持多種請求類型

Headers

Headers.Builder Http消息的頭欄位
前面看到了, 我們在初始化Request的時候 同時初始化了headers, this.headers = new Headers.Builder()

可以通過 header addHeader removeHeader headers 方法做一些操作


body

RequestBody類型,它是抽象類, 有些請求需要我們傳入body實例 ,我們在通過源碼來看一下:


如果是GET請求,body對象傳的是null
Get與head方法不能傳body對象 ,其他method是可以的

如果是POST請求,就需要我們去設定了

RequestBody解析

首先我們看一下RequestBody如何初始化??拿提交表單舉例:

RequestBody requestBody = new FormBody.Builder()
.add("username", "qinzishuai")
.add("password", "000000")
.build();

不出所料,也是Builder模式,而且RequestBody 是抽象類, FormBody是RequestBody的其中一種實現類 ,另一個實現類是MultipartBody
RequestBody源碼如下:

public abstract class RequestBody {

public abstract @Nullable MediaType contentType();


public long contentLength() throws IOException {
return -1;
}


public abstract void writeTo(BufferedSink sink) throws IOException;


public static RequestBody create(@Nullable MediaType contentType, String content) {
Charset charset = Util.UTF_8;
if (contentType != null) {
charset = contentType.charset();
if (charset == null) {
charset = Util.UTF_8;
contentType = MediaType.parse(contentType + "; charset=utf-8");
}
}
byte[] bytes = content.getBytes(charset);
return create(contentType, bytes);
}


public static RequestBody create(
final @Nullable MediaType contentType, final ByteString content) {
return new RequestBody() {
@Override public @Nullable MediaType contentType() {
return contentType;
}

@Override public long contentLength() throws IOException {
return content.size();
}

@Override public void writeTo(BufferedSink sink) throws IOException {
sink.write(content);
}
};
}


public static RequestBody create(final @Nullable MediaType contentType, final byte[] content) {
return create(contentType, content, 0, content.length);
}

}

核心方法有三個:

Call分析-同步異步請求流程newCall分析Call初始化

我們首先看一下在哪用到了Call:

final Call call = okHttpClient.newCall(request);

想起來了吧?無論是get還是post請求 都要生成call對象,在上面我們發現call實例需要一個okHttpClient與request實例 ,我們先點進Call類去看看:

public interface Call extends Cloneable {

Request request();

Response execute() throws IOException;

void enqueue(Callback responseCallback);

void cancel();

boolean isExecuted();

boolean isCanceled();
Call clone();

interface Factory {
Call newCall(Request request);
}
}

我們發現Call是個接口, 並定義了一些方方法(方法含義在注釋上)。
我們繼續看newCal()方法

@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false );
}

繼續點擊newRealCall()去:

private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}

static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {

RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}

從代碼中我們發現在newRealCall()中初始化了RealCall,RealCall中初始化了retryAndFollowUpInterceptor :

client:OkHttpClient 實例

originalRequest :最初的Request

forWebSocket :是否支持websocket通信

retryAndFollowUpInterceptor 從字面意思來說, 是重試和重定向攔截器 ,至於它有什麼作用我們繼續往下看

同步請求分析

Response response = call.execute();

我們點進execute()中查看:

@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}

從上面代碼得知步驟:
(1).通過 synchronized 保證線程同步,判斷是否已經執行過 ,如果是直接拋異常
(2). captureCallStackTrace(); 字面意思:捕獲調用堆棧跟蹤,我們通過源碼發現裡面涉及到了retryAndFollowUpInterceptor
(3). eventListener 回調CallStart()
(4). client.dispatcher().executed(this); 看到了dispatcher是不是很熟悉?之前在分析okhttpClient初始化的時候遇到了,我們點擊executed()方法進去:

synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}

發現把我們傳進來的realcall放到了runningSyncCalls隊列中,從字面意思來說就是正在運行的同步的調用隊列中,為什麼說是隊列呢?:

private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

(5).我們回到execute()繼續往下分析,剩下的代碼我們提取出三行代碼:

equesr result = getResponseWithInterceptorChain(); 生成一個Response 實例

eventListener.callFailed(this, e); :eventListener的callFailed回調

client.dispatcher().finished(this); :dispatcher實例的finished方法

不難看出,getResponseWithInterceptorChain()一定是此方法中的核心,字面意思是獲取攔截器鏈的響應,這就明白了,就是通過攔截器鏈處理後返回Response


getResponseWithInterceptorChain() 分析

Response getResponseWithInterceptorChain() throws IOException {

List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));

Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());

return chain.proceed(originalRequest);
}


從上面代碼不難看出, 對最初的request做了層層攔截,每個攔截器的原理我們放在以後的章節去講, 這裡就不展開了!


這裡需要強調的一下 interceptors.addAll(client.interceptors()); ,client.interceptors() 是我們自定義的攔截器 它是在哪定義的?如何添加?我們去OkHttpClient類中發現:

可以通過初始化okHttpClient實例 .addInterceptor的形式 添加。
另外這裡涉及到了責任鏈設計模式,下節具體講!


異步請求分析

call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d("okhttp_error",e.getMessage());
}

@Override
public void onResponse(Call call, Response response) throws IOException {
Gson gson=new Gson();

Log.d("okhttp_success",response.body().string());
}
});

點擊enqueue()查看:

@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

(1).通過 synchronized 保證線程同步,判斷是否已經執行過 ,如果是直接拋異常
(2). captureCallStackTrace(); 字面意思:捕獲調用堆棧跟蹤,我們通過源碼發現裡面涉及到了retryAndFollowUpInterceptor
(3). eventListener 回調CallStart()
(4). client.dispatcher().enqueue(new AsyncCall(responseCallback)); 調用了Dispatcher.enqueue()並傳入了一個new AsyncCall(responseCallback)實例,點擊AsyncCall查看:
AsyncCall 是RealCall的內部類!

final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;

AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}

String host() {
return originalRequest.url().host();
}

Request request() {
return originalRequest;
}

RealCall get() {
return RealCall.this;
}

@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {

Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}

AsyncCall繼承了NamedRunnable ,我們看下NamedRunnable是什麼:

public abstract class NamedRunnable implements Runnable {
protected final String name;

public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}

@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}

protected abstract void execute();
}

原來NamedRunnable 實現了Runnable 接口 是個線程類,在run()中 添加了抽象的execute();方法,看到這裡 我們應該有一個反應,那就是AsyncCall中具體的execute()應該在子線程執行 


我們繼續分析,client.dispatcher().enqueue(new AsyncCall(responseCallback)); 點擊進入enqueue():

synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}

如果正在運行的異步請求的隊列大小低於64並且 正在請求的host數量低於5,就會執行(滿足條件)

runningAsyncCalls.add(call);
executorService().execute(call);

這裡把 AsyncCall實例添加到 runningAsyncCalls中。
ExecutorService 表示線程池 繼續看 executorService():

public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}

其實就是生成了executorService 實例,這就明白了,AsyncCall實例放入線程池中執行了!

如果不滿足上面的請求數等條件:

readyAsyncCalls.add(call);

就會被添加到一個等待就緒的異步請求隊列中,目的是什麼呢???當然是等待時機再次添加到runningAsyncCalls中並放入線程池中執行,這塊邏輯在 AsyncCall類中的 execute() 至於原因我們繼續往下看!

剛才我們說了,如果條件滿足, AsyncCall實例就會在線程池中執行(.start),那我們直接去看run()中的 execute() :

@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {

Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}


上面代碼中得知, 首先通過層層攔截器鏈處理生成了response;然後通過一系列的判斷,responseCallback進行onResponse與onFailure回調,最後調用的Dispatcher.finifshed()


這裡需要注意的是 這裡的Dispatcher.finifshed(this)與同步中的Dispatcher.finifshed(this)不一樣 參數不同。


void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}


我們繼續看具體的finifshed()方法:

private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}

if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}


在線程同步的情況下 執行了promoteCalls();:

private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return;
if (readyAsyncCalls.isEmpty()) return;

for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();

if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}

if (runningAsyncCalls.size() >= maxRequests) return;
}
}

經過一系列的判斷, 對等待就緒的異步隊列進行遍歷,生成對應的AsyncCall實例,並添加到runningAsyncCalls中,最後放入到線程池中執行!這裡就是我們上面說到的等待就緒的異步隊列如何與runningAsyncCalls對接的邏輯。

總結同步請求流程:

生成call實例realcall

Dispatcher.executed()中的runningSyncCalls 添加realcall到此隊列中

通過 getResponseWithInterceptorChain() 對request層層攔截,生成Response

通過Dispatcher.finished(),把call實例從隊列中移除,返回最終的response


異步請求流程:

生成一個AsyncCall(responseCallback)實例(實現了Runnable)

AsyncCall實例放入了Dispatcher.enqueue()中,並判斷maxRequests (最大請求數)maxRequestsPerHost(最大host請求數)是否滿足條件,如果滿足就把AsyncCall添加到runningAsyncCalls中,並放入線程池中執行;如果條件不滿足,就添加到等待就緒的異步隊列,當那些滿足的條件的執行時 ,在Dispatcher.finifshed(this)中的promoteCalls();方法中 對等待就緒的異步隊列進行遍歷,生成對應的AsyncCall實例,並添加到runningAsyncCalls中,最後放入到線程池中執行,一直到所有請求都結束。

至此OKhttp整體流程就分析完了, 下一篇會分塊去分析,希望對大家有所幫助...

—————END—————


 
 創作不易,點個「在看

相關焦點

  • 阿里P8架構師力薦的 Java源碼解析及面試合集
    源碼解析和設計思路06 LinkedList 源碼解析07 List 源碼會問哪些面試題08 HasMap源碼解析19 LinkedBlockingQueue 源碼解析20 SynchronousQueue 源碼解析21 DelayQueue 源碼解析
  • Jetpack源碼解析--ViewModel基本使用及源碼解析
    1.背景Jetpack源碼解析系列文章:1. Android_Jetpack組件---Naviagtion源碼解析2. Jetpack源碼解析—Navigation為什麼切換Fragment會重繪?3. Jetpack源碼解析---用Lifecycles管理生命周期4.
  • 社交媒體登錄Spring Social的源碼解析
    本文就通過對Spring Social源碼進行一下解析,從而在我們後續開發第三方媒體平臺的登錄認證功能時,能更加的清晰。一、Spring Social結構化角度解析源碼Spring Social是一個幫助我們連接社交媒體平臺,方便在我們自己的應用上開發第三方登錄認證等功能的Spring 類庫。其中比較核心的類和接口,如下圖所示,我們來一一解析。
  • 抖音解析網站源碼 抖音解析保存在哪裡
    抖音解析網站源碼有沒有呢,這是很多有這方面需求的小夥伴們都關心的問題。就讓小編帶大家了解抖音解析保存在哪裡吧~
  • 開課吧雙十二教育節:助力學員輕鬆掌握Spring AOP源碼
    近年來,Spring AOP源碼已然成為國內網際網路大廠面試JAVA程式設計師必問問題。想要進入網際網路大廠的Java程式設計師,生澀難懂的Spring AOP源碼是一個繞不過去的坎。開課吧的「面試官最愛問的Spring AOP源碼全解析訓練營」,非常適合使用過Spring框架的小夥伴以及想要輕鬆進入網際網路大廠的JAVA程式設計師。
  • Spring-Task源碼解析
    this.registerBeanDefinitionParser("scheduler",newSchedulerBeanDefinitionParser());}schedulerSchedulerBeanDefinitionParser源碼
  • Spring Core Container 源碼分析三:Spring Beans 初始化流程分析
    本章節我們將詳細去闡述的是,Spring 容器是如何對 Singleton bean 進行初始化並註冊到當前容器的;與之相關的主要有兩個流程,解析 bean definitions 並註冊解析解析並註冊 bean definitions 流程該部分參考新的博文 Spring Core Container 源碼分析七:註冊 Bean DefinitionsDo Get Bean 流程Do Get Bean 流程的入口是 AbstractBeanFactory#doGetBean 方法,主流程圖如下,
  • 深入Mybatis源碼執行流程
    不過本質上第二種是在第一種的基礎之上實現的,所以下面就以第二種為主進行分析,進入到getMapper方法:mapperRegistry對象在上一篇分析過,是在解析xml中的mapper節點時註冊進去的,而這個對象中緩存了Mapper接口和對應的代理工廠
  • 深度學習框架Caffe源碼解析
    本文將從整體架構和底層實現的視角,對Caffe源碼進行解析。Caffe總體架構Caffe框架主要有五個組件,Blob,Solver,Net,Layer,Proto,其結構圖如下圖1所示。Solver負責深度網絡的訓練,每個Solver中包含一個訓練網絡對象和一個測試網絡對象。每個網絡則由若干個Layer構成。
  • Flink 全網最全資源(視頻、博客、PPT、入門、實戰、源碼解析、問答等持續更新)
    目前知識星球內已更新的系列文章:1、Flink 源碼解析 —— 源碼編譯運行2、Flink 源碼解析 —— 項目結構一覽3、Flink 源碼解析—— local 模式啟動流程4、Flink 源碼解析 —— standalonesession 模式啟動流程5、Flink 源碼解析 —— Standalone Session
  • 強大的反射功能詳解與應用源碼解析
    (以上均參考自《通用源碼閱讀指導書——MyBatis源碼詳解》)以上例子的來源於《通用源碼閱讀指導書——MyBatis源碼詳解》中的擴展閱讀部分提及的開源項目ObjectLogger( https://github.com/yeecode/ObjectLogger )。我們這裡只是ObjectLogger的一個非常簡化的實現。
  • Mybatis中SqlSource解析流程詳解
    在通過註解實現mapper的流程中是在MapperAnnotationBuilder類的parseStatement方法中對SqlSource進行初始化,初始化代碼如下圖:通過xml文件實現mapper的流程中是在XMLStatementBuilder類的parseStatementNode方法中對SqlSource進行初始化
  • 看到Mybatis源碼就感到煩躁,怎麼辦?
    配置文件的解析就是在這裡完成的。包括mybatis-config.xml和我們的Mapper.xml映射器文件。這一步我們關心的內容是:解析的時候做了什麼?產生了什麼對象,解析的結果放在哪裡的。因為這將意味著,我們後面使用的時候去哪裡獲取這項配置項內容。
  • DBLE 網絡模塊源碼解析之網絡 IO 基礎知識-愛可生
    研讀 DBLE 網絡模塊的源碼,能夠讓你對網絡 IO 的處理有更進一步的理解。為什麼連接 DBLE 能夠像連接 MySQL 一樣?為什麼 DBLE 的性能能夠如此高?希望通過本系列文章,能夠幫助大家對DBLE的網絡模塊有更深入的了解,更進一步,希望能夠幫助大家對高性能網絡 IO 有更深入的了解。
  • 源碼分析 — Activity的啟動流程
    原文連結:https://blog.csdn.net/lj19851227/article/details/82562115 前言 熟悉Activity的啟動流程和運行原理是一個合格的應用開發人員所應該具備的基本素質
  • Java8線程池ThreadPoolExecutor底層原理及其源碼解析
    線程池核心參數介紹下面將結合線程池中的任務提交流程加深理解.3.提交任務到線程池中的流程3.1 ThreadPoolExecutor#execute方法整體流程這裡以java.util.concurrent.ThreadPoolExecutor#execute方法為例, 畫一個簡單的圖:上圖中的worker可簡單理解為線程池中的一個線程, workers.size
  • 學習 koa 源碼的整體架構,淺析koa洋蔥模型原理和co原理
    前言這是學習源碼整體架構系列第七篇。整體架構這詞語好像有點大,姑且就算是源碼整體結構吧,主要就是學習是代碼整體結構,不深究其他不是主線的具體函數的實現。本篇文章學習的是實際倉庫的代碼。學習源碼整體架構系列文章如下:感興趣的讀者可以點擊閱讀。
  • 從源碼解讀Mybatis的初始化過程
    引言這篇文章呢,主要是講Mybtais的兩種方式的源碼剖析:傳統方式以及Mapper代理方式,初次探索Mybatis源碼,希望大佬勿噴並且指正錯誤,謝謝!2.主要構件及其相互關係3.層次結構圖下面這張圖就是Mybatis流程的層次結構圖,建議讀源碼的時候記得打開這張圖,思路才不會亂呢
  • 解析:深度學習框架Caffe源碼
    本文將從整體架構和底層實現的視角,對Caffe源碼進行解析。1.Caffe總體架構Caffe框架主要有五個組件,Blob,Solver,Net,Layer,Proto,其結構圖如下圖1所示。Solver負責深度網絡的訓練,每個Solver中包含一個訓練網絡對象和一個測試網絡對象。每個網絡則由若干個Layer構成。
  • 學習 redux 源碼整體架構,深入理解 redux 及其中間件原理
    這是學習源碼整體架構系列第八篇。整體架構這詞語好像有點大,姑且就算是源碼整體結構吧,主要就是學習是代碼整體結構,不深究其他不是主線的具體函數的實現。本篇文章學習的是實際倉庫的代碼。要是有人說到怎麼讀源碼,正在讀文章的你能推薦我的源碼系列文章,那真是太好了。