Okhttp source code, simple reading

Android 2022-05-14 14:59:56 阅读数:857

okhttpsourcecodesimplereading

For some unknown reason , In the near future, I will publish a large number of articles on theory or source code . Most of these articles are my notes from previous years , Or you didn't have time to take notes before . It is more suitable for developers who have a certain understanding of the relevant framework source code . Otherwise, it may cause discomfort , Manual formation .

Okhttp Use

image.png

Source code

Reading outline

  1. Synchronously call the network request process
  2. Asynchronously call the network request process
  3. Dispatcher Class code logic
  4. The logic of several interceptors

View the main procedure of synchronous call

  1. from newCall Start

call RealCall.newRealCall establish Call
image.png

  1. RealCall.newRealCall

image.png

  1. Because what we got in the last step Call The type is RealCall, So let's see RealCall.execute

Next, let's look at dispatcher().executed And then look at it getResponseWithInterceptorChain Method
image.png

  1. dispatcher().executed Methods and getResponseWithInterceptorChain Method

dispatcher().executed Method
image.png
getResponseWithInterceptorChain Method
In this method, a connector is built first , Then execute the interceptor
image.png

  1. Synchronous call complete

Asynchronously call the network request process

  1. Executing asynchronous requests in business code

image.png

  1. RealCall.enqueue

This method is finally adjusted to Dispatcher.enqueue
image.png

  1. Dispatcher.enqueue Scheduling asynchronous requests AsyncCall

image.png

  1. If the above method is called executeorService.execute Start executing thread pool , Because of our AsyncCall Realized NameRunnable, then NameRunnable It's realized again Runnable, So go and see NameRunnable.run Methods!

image.png

  1. AsyncCall.execute Perform the requested

image.png

Dispatcher Class code logic

Dispatcher The role of is to distribute requests , That is, he is used to manage Call And distribution Call Of . He also maintains a thread pool

Dispatcher Three queues are maintained internally :

  • runningSyncCalls Synchronization request queue - Used to execute synchronization requests
  • runningAsyncCalls Asynchronous request queue - Used to execute asynchronous requests
  • readyAsyncCalls Waiting request queue - When the number of concurrent asynchronous requests reaches the limit, put the request into the waiting queue

Dispatcher How to schedule asynchronous logic

Dispatcher There is not much complex logic in the , It mainly explains several important methods

  1. executorService Get thread pool
  2. setMaxRequests Set the maximum number of concurrent requests supported , This is mainly relative to asynchronous requests , It has nothing to do with the synchronization request
  3. enqueue Scheduling asynchronous requests
  4. cancelAll Cancel all requests
  5. promoteCalls Decide whether to add the requests in the waiting queue to the asynchronous queue for execution
  6. executed Perform synchronization request
  7. finished Two finish Method , Used to end synchronous requests and asynchronous requests respectively

The execution logic of the interceptor chain and the logic inside several interceptors

Interceptor execution logic, that is getResponseWithInterceptorChain Method

  1. Build and implement a chain of responsibility

It should be noted that client.interceptors() The interceptor obtained will be called anyway and client.networkInterceptors() The interceptor obtained will only call... Before the request goes to the real network request ( If the request uses a cache , Or if the real request ends before it starts, it will not call )

image.png

  1. RealInterceptorChain.proceed Method

Finally, the logic here can ensure the implementation of the responsibility chain
image.png

RetryAndFollowUpInterceptor retry , Redirect interceptor

The redirection interceptor actually maintains a loop internally . If the current request supports redirection , Then the responsibility chain will be re executed at the current position of the responsibility chain ( Will retry multiple times ). And that is , It attempts to reuse the previous connection

  1. see intercept Method

image.png
image.png
The following figure sameConnection In fact, it is to judge the absolute of the request host,port,scheme Is it consistent
image.png

BridgeInterceptor Bridge interceptors

  • The bridge interceptor will extract from the user's request parameters , Build request Request. Mainly for header Supplement and improve the contents of , This has saved us a lot of things ( For example, use HttpUrlconnection quite a lot header Parameters need to be handled by ourselves ).
  • Then use this request to access the network , Finally, use the network return results to build the response

intercept Reading,

  1. Processing requests header

image.png
image.png

  1. Request to get the response and process the response

image.png

CacheInterceptor Cache interceptor

I have done the following things
  • If the request cannot be obtained from the network and the cache is empty, the request fails
  • If the request cannot be obtained over the network , And there is a cache to directly return to the cache
  • If the request result returns 304, Indicates that the cache is still valid ( Back to response There is no physical content in ), Directly return the cache and refresh the cache
  • If the network request returns entity content , And the request supports caching , Write to cache

intercept Source code

The cache interceptor will decide whether to use the cached data according to the request information , And decide whether to store the cache after the request is completed
image.png
image.png
image.png
image.png

ConnectInterceptor Connection interceptor

ConnectInterceptor To get or create a connection in the cache , It's actually three handshakes . However, if there are available connections in the cache pool, you don't need to shake hands three times , This is the main function of the connector --- Save us three handshakes

Briefly describe the process of obtaining a connection ( Follow this idea when reading code ):

  1. First check StreamAllocation Current in class connection Is it available , If not available, turn off its socket

  2. Try to get the connection assignment from the connection pool to StreamAllocation.connection, If the acquisition is successful, reuse it directly

  3. If the first 2 Step did not succeed , And the request is http2, Then try to use again route Get multiplexed connections

  4. If the third part still doesn't get the connection , Then create a connection and add it to the cache pool

  5. If the connection is number 4 Created in step , You need three handshake connections before you can use

  6. If we were first 5 In step, after the connection is created , It is found that other requests have created a connection , Then we kill the connection we created ourselves , Then use the connection created by other requests to return .

  7. intercept Code

image.png

  1. newStream Method

image.png

  1. findHealthyConnection Loop through available connections

image.png

  1. The last step findConnection The real logic of obtaining the connection , The method is very long

findConnection There will be two attempts to get a connection from the connection pool , The first time is not to pass route To get . And the second time is through route To get .
The reason why there will be a second acquisition is http2 With multiplexing The concept of , Each connection can have multiple stream Of

http2 Multiplexing is the same tcp Links can execute multiple functions concurrently http request . I haven't seen it in the development process http2 Well , So there's no need to go too deep here

image.png
image.png

image.png
image.png

CallServerInterceptor Request network interceptor

intercept Method
image.png
image.png
image.png
image.png

summary

Okhttp You can use synchronous and asynchronous requests to request the network to obtain data , The request process is to build the request parameters , structure Call object , Then get the return data synchronously or asynchronously .

Both synchronous and asynchronous requests will eventually Call Dispatch to Dispatcher Class ,
The difference between them is :
Synchronous request mode will Call Join the synchronization request queue and execute the request .

The asynchronous request may put the request in the executing asynchronous request queue , It may also be added to the asynchronous request preparation queue . If the number of asynchronous requests we are currently executing is greater than the maximum number of concurrent requests , Then the request will be added to the preparation queue . After each asynchronous request is completed, it will try to add the request in the preparation queue to the executing queue .

It should be noted that asynchronous requests are executed using thread pool

Both methods will eventually call getResponseWithInterceptorChain Get the final data .

getResponseWithInterceptorChain It maintains a chain of responsibility . There are multiple connectors in this responsibility chain , Include 1 Retry the interceptor 、2 Bridge interceptors 、3 Cache interceptor 、4 Connection interceptor 、5 Network request interceptor . Our request parameters will be processed by these interceptors , The process is from 1->5, return Response The result will be from 5->1.

It actually includes custom interceptors

The subsequent process is to return the data to the calling place , The synchronization request directly returns the result , The asynchronous request uses the callback method to callback the result .

Interceptor RealInterceptorChain Why not use traversal to execute

  1. Traversal is not easy to handle interrupts and exceptions
  2. Our responsibility chain execution has two directions , During forward execution, the request parameters are passed forward for processing . In reverse, it will response Comes back . This can't be done by traversing
  3. Mechanism of retrying , For example, every time our responsibility chain moves forward new One RealInterceptorChain, In this way, if the request fails after the first execution , If we want to try again, we will start again from RetryAndFollowUpInterceptor Location new One RealInterceptorChain Carry out the second execution . In this way, the cache data of several new responsibility chain units requested for the first time will not affect our second execution . If you use traversal, you can't achieve this effect .

For example, when you use traversal to implement the chain of responsibility , When you want to try again, when the request gets CacheInterceptor, Find out CacheInterceptor It contains the logic we executed last time , He needs to deal with this residual logic more , It increases the workload .

版权声明:本文为[Android]所创,转载请带上原文链接,感谢。 https://qdmana.com/2022/134/202205141446337757.html