OSCache-緩存對象

在實際應用中除了JSP標籤庫,還可使用OSCache提供的Java API.下面我來介紹一個實用的Java類,使用GeneralCacheAdministrator來創建,刷新和管理緩存.html

GeneralCacheAdministrator類經常使用的方法有:
public Object getFromCache(String key) throws NeedsRefreshException; //從緩存中獲取一個key標識的對象.
public Object getFromCache(String key, int refreshPeriod) throws NeedsRefreshException; //從緩存中獲取一個key標識的對象. refreshPeriod刷新週期,標識此對象在緩存中保存的時間(單位:秒)java

public void putInCache(String key, Object content); //存儲一個由Key標識的緩存對象.
public void putInCache(String key, Object content, String[] groups); //存儲一個由Key標識的屬於groups中全部成員的緩存對象.緩存

public void flushEntry(String key); //更新一個Key標識的緩存對象.
public void flushGroup(String group); //更新一組屬於groupr標識的全部緩存對象.
public void flushAll(); //更新全部緩存.服務器

public void cancelUpdate(String key); //取消更新,只用於在處理捕獲的NeedsRefreshException異常並嘗試生成新緩存內容失效的時候.
public void removeEntry(String key); //從緩存中移除一個key標識的對象框架

案例:
一、對象Beanjsp

package com.ljq.test;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 對象Bean
 * 
 * @author 林計欽
 * @version 1.0 Aug 16, 2013 7:50:06 PM
 */
public class User {
    private int id;
    private String name;
    private String sex;
    private int age;
    private Date accessTime;

    public User(int id) {
        super();
        this.id = id;
        this.accessTime = new Date();
    }

    public String toString() {
        String date=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(accessTime);
        return "User info is : id=" + id + "  accessTime=" + date;
    }

    public User(String name, String sex, int age) {
        super();
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    public User() {
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Date getAccessTime() {
        return accessTime;
    }

    public void setAccessTime(Date accessTime) {
        this.accessTime = accessTime;
    }

}


二、緩存操做類工具

package com.ljq.test;

import com.opensymphony.oscache.base.NeedsRefreshException;
import com.opensymphony.oscache.general.GeneralCacheAdministrator;

/**
 * 緩存操做類
 * 
 * @author 林計欽
 * @version 1.0 Aug 16, 2013 7:48:07 PM
 */
public class BaseCache extends GeneralCacheAdministrator {
    private static final long serialVersionUID = 6239736145696260016L;
    private int refreshPeriod; // 過時時間(單位爲秒)
    private String keyPrefix; // 關鍵字前綴字符

    public BaseCache(String keyPrefix, int refreshPeriod) {
        super();
        this.keyPrefix = keyPrefix;
        this.refreshPeriod = refreshPeriod;
    }

    /**
     * 添加被緩存的對象
     * 
     * @param key
     * @param value
     */
    public void put(String key, Object value) {
        this.putInCache(this.keyPrefix + "_" + key, value);
    }

    /**
     * 刪除被緩存的對象
     * 
     * @param key
     */
    public void remove(String key){
        this.removeEntry(this.keyPrefix + "_" + key);  
    }
    
    /**
     * 刪除全部被緩存的對象
     */
    public void removeAll(){
        this.flushAll();
    }

    /**
     * 獲取被緩存的對象
     * 
     * @param key
     * @return
     * @throws Exception
     */
    public Object get(String key) throws NeedsRefreshException {
        return this.getFromCache(this.keyPrefix + "_" + key, this.refreshPeriod);
    }
    
    public void cancel(String key){
        this.cancelUpdate(key);
    }
    
    public void put(String key, Object value, String[] groups) {
        this.putInCache(this.keyPrefix + "_" + key, value, groups);
    }

    /**
     * 刪除該組的緩存對象
     * 
     * @param group
     */
    public void removeObjectByGroup(String group) {
        this.flushGroup(group);
    }


}


三、Cache管理類測試

package com.ljq.test;

/**
 * Cache管理類
 * 
 * @author 林計欽
 * @version 1.0 Aug 16, 2013 7:49:35 PM
 */
public class CacheManager {
    private boolean update=false;
    private BaseCache userCache;
    private static CacheManager instance;
    private static Object lock = new Object();

    private CacheManager() {
        // 這個根據配置文件來,初始BaseCache而已;
        userCache = new BaseCache("user", 120);
    }

    public static CacheManager getInstance() {
        if (instance == null) {
            synchronized (lock) {
                if (instance == null) {
                    instance = new CacheManager();
                }
            }
        }
        return instance;
    }

    public void putUser(User user) {
        userCache.put(user.getId() + "", user);
    }

    public void removeUser(String id) {
        userCache.remove(id);
    }
    
    public void removeAllUser() {
        userCache.removeAll();
    }

    public User getUser(int id) {
        try {
            //從Cache中得到
            return (User) userCache.get(id + "");
        } catch (Exception e) {
            //Cache中沒有則從DB庫獲取
            System.out.println(String.format("[%s]從db中獲取", id+""));
            User user = new User(id);
            //把獲取的對象再次存入Cache中
            this.putUser(user);
            update=true;
            return user;
        }finally{
            if(!update){
                //若是Cache中的內容更新出現異常,則終止該方法
                userCache.cancel(id + ""); //取消對id的更新
            }
        }
    }

}


四、測試類this

package com.ljq.test;

/**
 * 測試類
 * 
 * @author 林計欽
 * @version 1.0 Aug 16, 2013 7:51:19 PM
 */
public class UserCacheTest {
    public static void main(String[] args) {
        CacheManager cm = CacheManager.getInstance();
        UserCacheTest test = new UserCacheTest();
        test.print(cm);
    }

    public void print(CacheManager cm) {
        User user = null;
        for (int i = 0; i < 20; i++) {
            user = cm.getUser(100);
            System.out.println("<<" + i + ">>: " + user);
            if (i == 5) {
                // 刪除緩存id的對象
                cm.removeUser(100 + "");
            }
            if (i == 10) {
                // 刪除全部緩存的對象
                cm.removeAllUser();
            }
            // 睡眠部分
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                
            }
        }
    }

}

五、執行後控制檯打印的結果spa

[100]從db中獲取
<<0>>: User info is : id=100  accessTime=2013-08-16 21:20:27
<<1>>: User info is : id=100  accessTime=2013-08-16 21:20:27
<<2>>: User info is : id=100  accessTime=2013-08-16 21:20:27
<<3>>: User info is : id=100  accessTime=2013-08-16 21:20:27
<<4>>: User info is : id=100  accessTime=2013-08-16 21:20:27
<<5>>: User info is : id=100  accessTime=2013-08-16 21:20:27
[100]從db中獲取
<<6>>: User info is : id=100  accessTime=2013-08-16 21:20:33
<<7>>: User info is : id=100  accessTime=2013-08-16 21:20:33
<<8>>: User info is : id=100  accessTime=2013-08-16 21:20:33
<<9>>: User info is : id=100  accessTime=2013-08-16 21:20:33
<<10>>: User info is : id=100  accessTime=2013-08-16 21:20:33
[100]從db中獲取
<<11>>: User info is : id=100  accessTime=2013-08-16 21:20:38
<<12>>: User info is : id=100  accessTime=2013-08-16 21:20:38
<<13>>: User info is : id=100  accessTime=2013-08-16 21:20:38
<<14>>: User info is : id=100  accessTime=2013-08-16 21:20:38
<<15>>: User info is : id=100  accessTime=2013-08-16 21:20:38
<<16>>: User info is : id=100  accessTime=2013-08-16 21:20:38
<<17>>: User info is : id=100  accessTime=2013-08-16 21:20:38
<<18>>: User info is : id=100  accessTime=2013-08-16 21:20:38
<<19>>: User info is : id=100  accessTime=2013-08-16 21:20:38

小結及其引伸
緩存是在提高系統響應時經常使用的一種技術,在系統緩存上一般採用的是有頁面緩存、處理緩存和數據緩存這三種具體的類別,應該說這三種緩存在實現上仍是稍有不一樣,儘管底層的緩存實現是同樣的。

頁面緩存
頁面緩存是指對頁面中的內容片段進行緩存的方案。好比頁面中有一個部分是顯示欄目中的內容的,那麼就能夠緩存這個部分,在進行第二次請求的時候就直接從緩存中取出這部分的內容(其實就是這部分的html了),這種狀況下,緩存的做用其實很是明顯,在典型的action+service+dao這樣的結構中,在採用頁面緩存後就意味着不須要通過action、service、dao這些層次的處理了,而是直接就返回了,對於系統響應速度的提高來講是很是明顯的。

頁面緩存一般採用oscache來進行實現,oscache提供了一個jsp tag,可經過這個tag來包含須要緩存的內容部分,固然,緩存的這個內容部分須要有對服務器的請求或邏輯計算等的,可想而知,去緩存一段靜態html是沒有意義的。

其次須要定義緩存的這段內容的key,例如咱們要去緩存頁面中某個欄目的某頁的內容,對於這段內容而言惟一的key就是欄目ID以及當前頁數,這樣就組成了這段緩存的key了,其實這個部分看起來好像是很簡單,但有些時候會很麻煩,要仔細的想清楚這段內容的惟一的標識的key究竟是什麼,^_^,一般的作法其實能夠從action中須要獲取的參數或service接口的參數來決定....

頁面緩存中還須要作的一個步驟就是通知緩存須要更新,頁面緩存和其餘緩存稍有不一樣,須要告訴它,這個時候不能再使用緩存中的內容了,須要從後臺再從新獲取來生成新的緩存內容,這個其實很簡單,由於很難在後臺發生變化的時候本身來更新緩存的內容,只能是去通知它,而後讓它再次發起請求來生成新的內容放入緩存中。

頁面的緩存的使用對於系統的響應速度確實會有很大的提高,在實現頁面緩存時最麻煩的主要是緩存的key的定義以及緩存更新的通知,緩存key的定義這個天然框架是無法解決的,不過緩存更新的通知其實在框架中能夠考慮一種通知模型的,^_^,就像事件通知那樣........在實際的項目中,能夠本身去實現一個這樣的通知模型或者就是簡單的採用單例方式來標識某個key是否須要更新。

頁面緩存在實際的項目中使用很是的多。

處理緩存
處理緩存是指對於action、service、dao或者系統層次中的某方法進行緩存,說直接點,就是對某個類的某個方法的結果作緩存,這樣在下次進行徹底相同的請求的時候就能夠直接取緩存了,這種響應速度的提高也是很是明顯的。

處理緩存在如今的狀況下其實採用任務的緩存工具包均可以實現,如oscache、ehcache、jbosscache等,但目前尚未處理緩存框架的出現,這個和處理緩存是否應該存在的意義也是有關係的,處理緩存框架要作到的其實就像攔截同樣的方式,和oscache tag相似。

一樣,處理緩存的麻煩也在於怎麼樣去定義這個key,不少狀況下能夠根據方法的輸入做爲key,方法的輸出做爲key的值,但也會有其餘一些複雜的狀況,這個時候定義key就會變得複雜些了。

處理緩存一樣有通知更新緩存的狀況,和頁面緩存基本是同樣的。

應該說,處理緩存和頁面緩存很是的類似,從實現上來講基本是徹底一致的,在使用上來說處理緩存使用的好像很少。

數據緩存
數據緩存估計你們都很熟悉,就是對系統的數據進行緩存的方式,典型的就是Hibernate的一級、二級數據緩存。

數據緩存在實現上若是是用hibernate的話更多的是直接使用hibernate的一級、二級以及查詢緩存,若是本身要實現的話能夠去參考hibernate的實現機制。

數據緩存的key在一級、二級緩存中採用的都是數據的標識鍵的值的方式,查詢緩存採用的是查詢參數、查詢語句的方式。

數據緩存的更新則是hibernate在進行存儲時直接更新緩存的內容,而對於查詢緩存則是採用所有直接清除的方式,這樣在下次進行查詢時天然會從新去查詢,^_^,你們可能會想,爲何頁面緩存和處理緩存不採用這樣的方式來實現緩存的更新,稍微想一想就知道了,在後臺發生改變的時候實際上是不知道須要移除哪些key的,因此hibernate爲了不這個麻煩,採用的就是當數據一旦發生改變的時候就清除所有的查詢緩存,而不是隻去清除相關的緩存,其實這裏能夠採用一種訂閱式的模型,呵呵,固然,也增長了框架的複雜度。

數據緩存使用的應該是最多的,效果也是很明顯的。

以上三種緩存是目前緩存實現時一般碰到的三種情況,裏面按使用的多少來排序應該是:數據緩存、頁面緩存和處理緩存;實現的難度上從難到易的順序應該是:處理緩存、頁面緩存、數據緩存;對於系統響應速度提高的效果來講從最好到好的順序應該是:頁面緩存、處理緩存、數據緩存。

相關文章
相關標籤/搜索