Redis快取物件的實現原理
截止到目前為止,在redis官方的文件和實現裡面並沒有針對object 物件快取的方法,然而,在我們的實際開發需要中,在很多時候我們是需要進行物件快取的,並且可以正確的讀取出來! 在筆者正在開發的紅包專案中,針對每天紅包就需要使用的物件快取,並可以隨時修改快取物件中的紅包數量值等資訊!那麼具體實現呢?
在官方提供的方法中,我們找到了有這麼一個操作方法:
jedis.set(byte[], byte[])
看這個方法,是進行位元組碼操作的,這讓我們很容易想到在一些遠端方法呼叫中,我們傳遞物件同樣傳遞的是位元組碼,是不是可以參考呢?
首先,既然需要對物件進行位元組操作,即可寫和可讀的操作,為了保證這個原則,那麼快取物件需要實現Serializable 介面,進行序列化和反序列化!
涉及到的知識點:
1: Serializable (介面,實現此介面的物件可以進行序列化)
2: ByteArrayOutputStream,ObjectOutputStream 物件轉換為位元組碼輸出流
3: ByteArrayInputStream ,ObjectInputStream 位元組碼轉換為物件的輸入流
瞭解瞭如上三點知識後,我們就可以對物件進行快取操作了!
示例程式碼如下,包括了物件快取和List 物件陣列快取,需要宣告的是,放入list陣列中的物件同樣需要實現Serializable 介面:
public class ObjectsTranscoder extendsSerializeTranscoder {<span style="color:#808000;">@SuppressWarnings</span>(<span style="color:#008000;"><strong>"unchecked"</strong></span>) <span style="color:#808000;">@Override
public byte[] serialize(Object value) {
if (value == null) {
throw new NullPointerException(“Can’t serialize null”
<span style="color:#808000;">@SuppressWarnings</span>(<span style="color:#008000;"><strong>"unchecked"</strong></span>)
<span style="color:#808000;">@Override
public Object deserialize(byte[] in) { Object result = null; ByteArrayInputStream bis = null; ObjectInputStream is = null; try { if (in != null) { bis = new ByteArrayInputStream(in); is = new ObjectInputStream(bis); result = is.readObject(); is.close(); bis.close(); } } catch (IOException e) { logger.error(String.format(“Caught IOException decoding %d bytes of data”, in == null ? 0 : in.length) + e); } catch (ClassNotFoundException e) { logger.error(String.format(“Caught CNFE decoding %d bytes of data”, in == null ? 0 : in.length) + e); } finally { close(is); close(bis); } return result; } }
物件的轉換示例如上程式碼:
陣列快取程式碼:
public class ListTranscoder<M extends Serializable> extends SerializeTranscoder {<span style="color:#808000;">@SuppressWarnings</span>(<span style="color:#008000;"><strong>"unchecked"</strong></span>) <span style="color:#000080;"><strong>public </strong></span>List<<span style="color:#20999d;">M</span>> deserialize(<span style="color:#000080;"><strong>byte</strong></span>[] in) { List<<span style="color:#20999d;">M</span>> list = <span style="color:#000080;"><strong>new </strong></span>ArrayList<>(); ByteArrayInputStream bis = <span style="color:#000080;"><strong>null</strong></span>; ObjectInputStream is = <span style="color:#000080;"><strong>null</strong></span>; <span style="color:#000080;"><strong>try </strong></span>{ <span style="color:#000080;"><strong>if </strong></span>(in != <span style="color:#000080;"><strong>null</strong></span>) { bis = <span style="color:#000080;"><strong>new </strong></span>ByteArrayInputStream(in); is = <span style="color:#000080;"><strong>new </strong></span>ObjectInputStream(bis); <span style="color:#000080;"><strong>while </strong></span>(<span style="color:#000080;"><strong>true</strong></span>) { <span style="color:#20999d;">M </span>m = (<span style="color:#20999d;">M</span>)is.readObject(); <span style="color:#000080;"><strong>if </strong></span>(m == <span style="color:#000080;"><strong>null</strong></span>) { <span style="color:#000080;"><strong>break</strong></span>; } list.add(m); } is.close(); bis.close(); } } <span style="color:#000080;"><strong>catch </strong></span>(IOException e) { <span style="color:#660e7a;"><em>logger</em></span>.error(String.<span style="font-style:italic;">format</span>(<span style="color:#008000;"><strong>"Caught IOException decoding %d bytes of data"</strong></span>, in == <span style="color:#000080;"><strong>null </strong></span>? <span style="color:#0000ff;">0 </span>: in.<span style="color:#660e7a;"><strong>length</strong></span>) + e); } <span style="color:#000080;"><strong>catch </strong></span>(ClassNotFoundException e) { <span style="color:#660e7a;"><em>logger</em></span>.error(String.<span style="font-style:italic;">format</span>(<span style="color:#008000;"><strong>"Caught CNFE decoding %d bytes of data"</strong></span>, in == <span style="color:#000080;"><strong>null </strong></span>? <span style="color:#0000ff;">0 </span>: in.<span style="color:#660e7a;"><strong>length</strong></span>) + e); } <span style="color:#000080;"><strong>finally </strong></span>{ close(is); close(bis); } <span style="color:#000080;"><strong>return </strong></span>list; } <span style="color:#808000;">@SuppressWarnings</span>(<span style="color:#008000;"><strong>"unchecked"</strong></span>) <span style="color:#808000;">@Override
public byte[] serialize(Object value) { if (value == null) throw new NullPointerException(“Can’t serialize null”);
List<<span style="color:#20999d;">M</span>> values = (List<<span style="color:#20999d;">M</span>>) value;
<span style="color:#000080;"><strong>byte</strong></span>[] results = <span style="color:#000080;"><strong>null</strong></span>;
ByteArrayOutputStream bos = <span style="color:#000080;"><strong>null</strong></span>;
ObjectOutputStream os = <span style="color:#000080;"><strong>null</strong></span>;
<span style="color:#000080;"><strong>try </strong></span>{
bos = <span style="color:#000080;"><strong>new </strong></span>ByteArrayOutputStream();
os = <span style="color:#000080;"><strong>new </strong></span>ObjectOutputStream(bos);
<span style="color:#000080;"><strong>for </strong></span>(<span style="color:#20999d;">M </span>m : values) {
os.writeObject(m);
}
<span style="color:#808080;"><em>// os.writeObject(null);
os.close(); bos.close(); results = bos.toByteArray(); } catch (IOException e) { throw new IllegalArgumentException(“Non-serializable object”, e); } finally { close(os); close(bos); }
<span style="color:#000080;"><strong>return </strong></span>results;
}
}
通過以上操作即可以實現物件的快取和讀取了!
雖然自己實現了,還是希望redis官方儘快提供物件的快取操作吧!