1. 程式人生 > >Redis快取物件的實現原理

Redis快取物件的實現原理

      截止到目前為止,在redis官方的文件和實現裡面並沒有針對object 物件快取的方法,然而,在我們的實際開發需要中,在很多時候我們是需要進行物件快取的,並且可以正確的讀取出來! 在筆者正在開發的紅包專案中,針對每天紅包就需要使用的物件快取,並可以隨時修改快取物件中的紅包數量值等資訊!那麼具體實現呢?

       在官方提供的方法中,我們找到了有這麼一個操作方法: 

jedis.set(byte[], byte[])

看這個方法,是進行位元組碼操作的,這讓我們很容易想到在一些遠端方法呼叫中,我們傳遞物件同樣傳遞的是位元組碼,是不是可以參考呢?

首先,既然需要對物件進行位元組操作,即可寫和可讀的操作,為了保證這個原則,那麼快取物件需要實現Serializable 介面,進行序列化和反序列化!

涉及到的知識點:

1: Serializable (介面,實現此介面的物件可以進行序列化)

2: ByteArrayOutputStream,ObjectOutputStream 物件轉換為位元組碼輸出流

3: ByteArrayInputStream ,ObjectInputStream 位元組碼轉換為物件的輸入流

瞭解瞭如上三點知識後,我們就可以對物件進行快取操作了!

示例程式碼如下,包括了物件快取和List 物件陣列快取,需要宣告的是,放入list陣列中的物件同樣需要實現Serializable 介面:

public class ObjectsTranscoder extends 
SerializeTranscoder {
<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”

); } byte[] result = null; ByteArrayOutputStream bos = null; ObjectOutputStream os = null; try { bos = new ByteArrayOutputStream(); os = new ObjectOutputStream(bos); os.writeObject(value); os.close(); bos.close(); result = bos.toByteArray(); } catch (IOException e) { throw new IllegalArgumentException(“Non-serializable object”, e); } finally { close(os); close(bos); } return result; }

<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&lt;<span style="color:#20999d;">M</span>&gt; deserialize(<span style="color:#000080;"><strong>byte</strong></span>[] in) {
    List&lt;<span style="color:#20999d;">M</span>&gt; list = <span style="color:#000080;"><strong>new </strong></span>ArrayList&lt;&gt;();
    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&lt;<span style="color:#20999d;">M</span>&gt; values = (List&lt;<span style="color:#20999d;">M</span>&gt;) 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官方儘快提供物件的快取操作吧!