1. 程式人生 > >備忘:ehcache的簡單使用說明

備忘:ehcache的簡單使用說明

ehcache 中的主要概念

  1. CacheManager:快取管理器。負責Cache的建立、訪問、移除。
  2. Cache:快取例項。所有的cache都實現了介面Ehcache。每個cache都有名字和屬性,且包含N個Element。
  3. Element:存放於Cache中的原子單位。有一個key、一個value以及關於訪問的記錄。Element被放進到Cache或者被從Cache移除。Element也可能會由於過期被移除,這依賴於Cache的配置。

本文中使用的相關軟體版本

<dependency>
    <groupId>net.sf.ehcache</groupId
>
<artifactId>ehcache</artifactId> <version>2.10.4</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> </dependency>

log4j 配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//log4j/log4j Configuration//EN" "log4j.dtd">
<log4j:configuration>
    <!--輸出到控制檯 -->
    <appender name="consoleAppender" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout"
>
<param name="ConversionPattern" value="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n" /> </layout> </appender> <logger name="org.springframework"> <level value="INFO"/> </logger> <logger name="net.sf.ehcache"> <level value="DEBUG"/> </logger> <root> <level value="INFO" /> <appender-ref ref="consoleAppender" /> </root> </log4j:configuration>

程式碼方式使用ehcache

public static void main(String[] args) {  
    // 建立快取管理器
    CacheManager cm1 = CacheManager.create();
    // 建立一個快取例項
    Cache myCache = new Cache("myCache", 5000, false, false, 5, 2);

    // 在快取管理器中新增快取例項
    cm1.addCache(myCache);

    // 在快取管理器中獲取一個快取例項
    // oneCache = cm1.getCache("oneCache");

    myCache.put(new Element("key1", "value1"));// 新增快取元素
    myCache.put(new Element("key2", "value2"));// 新增快取元素

    int elementCount = myCache.getSize();// 獲取快取元素個數

    System.out.printf("快取%s中Elemet個數為:%s\n", "myCache", elementCount);

    // 獲取物件值
    Element el = myCache.get("key1");
    Object obj = el.getObjectValue();
    System.out.printf("Element Key:%s,Value:%s\n", "key1", obj.toString());
    // 刪除快取
    myCache.remove("key1");
    if (myCache.isKeyInCache("key1")) {
        System.out.println("Element: key1 IN myCache");
    } else {
        System.out.println("Element: key1 NOT IN myCache");
    }

    CacheManager cm2 = CacheManager.create();
    System.out.println(cm1 == cm2);
}  

xml方式使用ehcache

配置ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="ehcacheDemo">

    <!-- 磁碟快取位置 -->
    <diskStore path="java.io.tmpdir" />

    <!--沒有特殊設定時系統預設使用此設定 -->
    <defaultCache maxElementsInMemory="1000" eternal="false"
        timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
        maxElementsOnDisk="10000" diskPersistent="false"
        diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" />

    <cache name="demoCache" maxElementsInMemory="2000" eternal="false"
        timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
        memoryStoreEvictionPolicy="LRU" />
</ehcache>

maxElementsInMemory:cache中最多可以存放的元素的數量。

如果放入cache中的元素超過這個數值,有兩種情況:
1. 若overflowToDisk的屬性值為true,會將cache中多出的元素放入磁碟檔案中。
2. 若overflowToDisk的屬性值為false,會根據memoryStoreEvictionPolicy的策略替換cache中原有的元素。

eternal:是否永駐記憶體。

如果值是true,cache中的元素將一直儲存在記憶體中,不會因為時間超時而丟失。
所以這個值設定為true時,timeToIdleSeconds和timeToLiveSeconds兩個屬性的值就不起作用了。

timeToIdleSeconds:訪問cache中元素的最大間隔時間。

如果超過這個時間沒有訪問這個cache中的某個元素,那麼這個元素將被從cache中清除。

timeToLiveSeconds:cache中元素的生存時間。

cache中的某個元素從建立到消亡的時間,從建立開始計時,當超過這個時間,這個元素將被從cache中清除。

overflowToDisk :

溢位是否寫入磁碟。系統會根據標籤<diskStore path="java.io.tmpdir"/>中path的值查詢對應的屬性值。

diskExpiryThreadIntervalSeconds:磁碟快取的清理執行緒執行間隔

每經過多少秒,執行一次清理執行緒

memoryStoreEvictionPolicy:記憶體儲存與釋放策略。

LRU -Least Recently Used
LFU -Least Frequently Used
FIFO-First In First Out, the oldest element by creation time

diskPersistent:是否持久化磁碟快取。

當這個屬性的值為true時,系統在初始化的時候會在磁碟中查詢檔名為cache名稱,字尾名為index的的檔案,如CACHE_FUNC.index。
這個檔案中存放了已經持久化在磁碟中的cache的index,找到後把cache載入到記憶體。
要想把cache真正持久化到磁碟,寫程式時必須注意,在是用net.sf.ehcache.Cache的void put (Element element)方法後要使用void flush()方法。

程式碼

public static void main(String[] args) {
    String cacheName = "demoCache";// 與ehcache.xml中的cache.name對應
    String elementKey = "k1";

    // 建立快取管理器
    CacheManager cm1 = new CacheManager();

    // 根據cacheName取得cache的例項
    Cache cache = cm1.getCache(cacheName);

    // 將資料Element放入到cache例項中
    cache.put(new Element(elementKey, "Element_1"));

    // 取值
    Cache cache2 = cm1.getCache(cacheName);
    Element element = cache2.get(elementKey);

    // Print the value
    System.out.printf("cache2中element儲存的值為:%s\n", element.getObjectValue());
}  

CacheManager建立模式

單例模式

在程式碼中使用CacheManager.create(…)建立CacheManager,返回的是已經存在的ehcache.xml配置對應的單例CacheManager,如果不存在,則建立一個。
參考 net.sf.ehcache.CacheManager 的程式碼:

    /**
     * Default name if not specified in the configuration/
     */
    public static final String DEFAULT_NAME = "__DEFAULT__";

    /**
     * The Singleton Instance.
     */
    private static volatile CacheManager singleton;

    ......

    public static CacheManager create() throws CacheException {
        if (singleton != null) {
            LOG.debug("Attempting to create an existing singleton. Existing singleton returned.");
            return singleton;
        }
        synchronized (CacheManager.class) {
            if (singleton == null) {
                singleton = newInstance();
            } else {
                LOG.debug("Attempting to create an existing singleton. Existing singleton returned.");
            }
            return singleton;
        }
    }
    ......
     private static CacheManager newInstance(Configuration configuration, String msg) throws CacheException {
        synchronized (CacheManager.class) {
            String name = configuration.getName();
            if (name == null) {
                name = DEFAULT_NAME;
            }
            CacheManager cacheManager = CACHE_MANAGERS_MAP.get(name);
            if (cacheManager == null) {
                LOG.debug(msg);
                cacheManager = new CacheManager(configuration);
            }
            return cacheManager;
        }
    }

多例項模式

在程式碼中使用new CacheManager(…)方法建立CacheManger,每次呼叫都會返回一個新的CacheManger。

注意:2.5之後的版本,不允許在同一個JVM中有多個相同名字的CacheManager。

也就是說,如果在程式碼中使用

CacheManager cm1 = new CacheManager();
CacheManager cm2 = new CacheManager();

會報錯。

Exception in thread "main" net.sf.ehcache.CacheException: Another CacheManager with same name 'ehcacheDemo' already exists in the same VM. Please provide unique names for each CacheManager in the config or do one of following:
1. Use one of the CacheManager.create() static factory methods to reuse same CacheManager with same name or create one if necessary
2. Shutdown the earlier cacheManager before creating new one with same name.

因為new CacheManger()沒有指定各自的配置檔案,所以都載入了classpath下的ehcache.xml,導致了CacheManger的名字(即:ehcacheDemo)衝突。

所以程式中要使用兩個CacheManager的話,只要修改下設定一下就可以了。
1. 不同的配置檔案:ehcache1.xml,ehcache2.xml
2. 不同的ehcache.name:ehcacheDemo1,ehcacheDemo2。
3. 不同的構造引數:

CacheManager cm1 = new CacheManager(TestEhcache.class.getResourceAsStream("/ehcache1.xml"));
CacheManager cm2 = new CacheManager(TestEhcache.class.getResourceAsStream("/ehcache2.xml"));