Jedis源碼分析共有四個章節,如下爲各章連接:html
首先看Jedis的內部結構,圖2-1中用橘色框標出了主要支架, 爲突出主要架構,或有稍許內容沒有標出。java
圖1-1 Jedis的類結構
Jedis以輸入的命令參數是否爲二進制,將處理請求的具體實現部署在兩個類中,例如Jedis
和BinaryJedis
,Client
和BinaryClient
。與Redis服務器的鏈接信息(Socket,host,port……)封裝在Client
的基類Connection
中。BinaryJedis
類中提供了Client,Pipeline和Transcation變量,對應3種請求模式。redis
Jedis jedis = new Jedis("localhost", 6379, 15000); Transaction t = jedis.multi(); Pipeline pipeline = jedis.pipelined();
Jedis經過傳入Redis服務器地址(host,port)開始初始化,而後在BinaryJedis裏實例化Client。Client經過Socket維持客戶端與Redis服務器的鏈接與溝通。
前文提到Transaction和Pipeline很類似,它們繼承同一個基類MultiKeyPipelineBase
。區別在於Transaction在實例化的時候,就自動發送MULTI命令,開啓事務模式,而Pipeline則按狀況手動開啓,它們均依靠Client發送命令。如下是Transaction和Pipeline初始化的具體實現:segmentfault
//BinaryJedis類 public Transaction multi() { client.multi(); transaction = new Transaction(client); return transaction; } public Pipeline pipelined() { pipeline = new Pipeline(); pipeline.setClient(client); return pipeline; }
下面經過發送一個get key
的命令,看看,這三種模式是如何運轉的。服務器
以get key
爲例,爲突出主要步驟,部分代碼略有縮減。
用法:架構
jedis.get("foo");
圖3-1 Clinet模式的時序圖 socket
圖3-2 Client模式的調用流程工具
圖3-1和3-2是client模式下,發送請求,讀取回復的具體實現。能夠清楚看到,在每次發送命令前,會先經過connect()
方法判斷是否已經鏈接,若未鏈接則進行以下操做:源碼分析
Protocol是一個通信工具類,將Redis的各種執行關鍵字存儲爲靜態變量,能夠直觀調用命令,例如Protocol.Command.GET
。同時,將命令包裝成符合Redis的統一請求協議,回覆消息的處理也是在這個類進行,先經過通信協提取出當次請求的回覆消息,將Object類型的消息,格式化爲String,List等具體類型,若是回覆消息有Error則以異常的形式拋出。ui
圖3-3 Transaction和Pipeline的類結構
圖3-3 是Transaction和Pipeline兩個類的的類結構。能夠看到Pipeline和Transaction都繼承自MultiKeyPipelineBase
,其中,MultiKeyPipelineBase
和PipelineBase
的區別在於處理的命令不一樣,內部均調用Client發送命令。從如下用例也能夠看出二者的操做也十分相似。Pipeline有一個內部類對象MultiResponseBuilder
,前文提到,當Redis事務結束時,會以List的形式,一次性返回全部命令的執行結果。MultiResponseBuilder
對象就是用於,當Pipeline開始其實模式後,在事務結束時,存儲全部返回結果。
Queable用一個LinkedList裝入每一個命令的返回結果,Response<T>
是一個泛型,set(Object data)
方法傳入格式化以前的結果,get()
方法返回格式化以後的結果。
Pipeline的使用方法:
Pipeline p = jedis.pipelined(); //只發送命令,不讀取結果,此時的Response<T>沒有數據 Response<String> string = p.get("string"); Response<String> list = p.lpop("list"); Response<String> hash = p.hget("hash", "foo"); Response<Set<String>> zset = p.zrange("zset", 0, -1); Response<String> set = p.spop("set"); //一次讀取全部response.此時的Response<T>有數據 p.sync(); assertEquals("foo", string.get()); assertEquals("foo", list.get()); assertEquals("bar", hash.get()); assertEquals("foo", zset.get().iterator().next()); assertEquals("foo", set.get()); Transactions使用方法: //開啓事務 Transaction t = jedis.multi(); //命令進入服務端的待執行隊列 Response<String> string = t.get("string"); Response<String> list = t.lpop("list"); Response<String> hash = t.hget("hash", "foo"); Response<Set<String>> zset = t.zrange("zset", 0, -1); Response<String> set = t.spop("set"); //發送EXEC指令,執行全部命令,並返回結果 t.exec(); assertEquals("foo", string.get()); assertEquals("foo", list.get()); assertEquals("bar", hash.get()); assertEquals("foo", zset.get().iterator().next()); assertEquals("foo", set.get());
圖3-4 Pipeline的調用時序圖
圖3-5 Pipeline的調用流程
圖3-4,3-5 顯示了Pipeline從發送請求到讀取回復的具體實現,Transaction的實現與其相似,於是沒有另外作圖說明。由上圖可見,Pipeline經過Client發送命令,Client在sendCommand
時,會同時執行pipelinedCommands++
,記錄發送命令的條數(參見圖3-5)。以後,返回一個Response<T>
實例,並將這個實例塞入了pipelinedResponses
隊列中。Response<T>
主要有3個屬性:
剛發送消息後,Response<T>
裏面的data
和response
是空值,只有格式化的方式builder
。Sync()
用於一次性讀取全部回覆,首先調用client的getAll()
方法,getAll()
方法根據以前記錄的pipelinedCommands
和Redis通信協議,讀取相同條數的回覆消息到一個List,並返回給Pipeline。隨後遍歷這個List,逐個將回復消息賦給pipelinedResponses
中每一個Response<T>
的data
。
在執行Response<T>.get()
命令時,Response<T>
裏面data
已經有值了,可是是Object類型的,於是還要調用build()
方法,作一次數據轉換,返回格式化以後的數據。
以上就是Pipeline的主要工做流程。Transaction的exec()
方法和sync()
很類似,下文爲exec()
的具體實現。
public List<Object> exec() { // 清空inputstream裏面的全部數據,忽略QUEUED or ERROR回覆 client.getMany(getPipelinedResponseLength()); //發送EXEC指令,讓服務端執行全部命令 client.exec(); //事務結束 inTransaction = false; //從inputStream中讀取全部回覆 List<Object> unformatted = client.getObjectMultiBulkReply(); if (unformatted == null) { return null; } //和sync()同樣 List<Object> formatted = new ArrayList<Object>(); for (Object o : unformatted) { try { formatted.add(generateResponse(o).get()); } catch (JedisDataException e) { formatted.add(e); } } return formatted; }
本節雖未將Pipeline和Transaction的方法實現盡述,但也大同小異。關鍵點在於理解第一章介紹的3類請求邏輯。