javaWeb Cache技術――OSCache(轉-全)


什么是osCache? 它是:http://baike.baidu.com/view/1835163.htm?fr=aladdin

OSCache使用指南 

一、下載安裝 

OSCache是一個基於web應用的組件,他的安裝工作主要是對web應用進行配置,大概的步驟如下: 

1. 下載、解壓縮OSCache 

從http://www.opensymphony.com/oscache/download.html下載合適的OSCache版本, 解壓縮下載的文件到指定目錄 。 

2、新建立一個web應用 

3、將OSCache集成到web項目當中。 

       (1)從解壓縮目錄取得oscache.jar 文件放到 /WEB-INF/lib 或相應類庫目錄中,jar文件名可能含有版本號和該版本的發布日期信息等。 

       (2)將etc目錄下的oscache.properties、oscache.tld放入WEB-INF/class目錄(確切說是放在項目的src目錄下,編譯的時候會自動生成在WEB-INF/class目錄)。 

       (3)配置項目對應的oscache.properties參數信息。 

       (4)具體使用 

              A、緩存對象:直接調用API的接口即可(詳見[Java]用OSCache進行緩存對象) 

              B、部分頁面緩存:使用OSCache提供的taglib(修改web.xml文件,在web.xml文件中增加下面的內容,增加對OSCache提供的taglib的支持:<taglib> <taglib-uri>oscache</taglib-uri> <taglib-location>/WEB-INF/classes/ oscache.tld</taglib-location></taglib>或者在jsp頁面使用以下標簽 

<%@ taglib uri="/WEB-INF/classes/oscache.tld" prefix="cache"%>) 

              C、整個頁面的緩存:用CashFilter實現頁面級緩存,可緩存單個文件、緩存URL pattern和自己設定緩存屬性的緩存。 

<filter> 

<filter-name>CacheFilter</filter-name> 

<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class> 

<init-param> 

<param-name>time</param-name> 

<param-value>600</param-value> 

</init-param> 

<init-param> 

<param-name>scope</param-name> 

<param-value>session</param-value> 

</init-param> 

</filter> 

<filter-mapping> 

<filter-name>CacheFilter</filter-name> 

<!-對所有jsp頁面內容進行緩存--> 

<url-pattern>*.jsp</url-pattern> 

</filter-mapping> 

[注] 只有客戶訪問時返回http頭信息中代碼為200(也就是訪問已經成功)的頁面信息才能夠被緩存 


三、OSCache的基本用法(緩存JSP頁面中部分) 

(一):Cache-OSCache提供的緩存標簽 

這是OSCache提供的標簽庫中最重要的一個標簽,包括在標簽中的內容將應用緩存機制進行處理,處理的方式將取決於編程者對cache標簽屬性的設置。 

第一次請求到達時,標簽中的內容被處理並且緩存起來,當下一個請求到達時,緩存系統會檢查這部分內容的緩存是否已經失效,主要是以下幾項: 

1. 緩存時間超過了cache標簽設置的time或者duration屬性規定的超時時間 

2. cron屬性規定的時間比緩存信息的開始時間更晚 

3. 標簽中緩存的內容在緩存后又被重新刷新過 

4. 其他緩存超期設定 

如果符合上面四項中的任何一項,被緩存的內容視為已經失效,這時被緩存的內容將被重新處理並且返回處理過后的信息,如果被緩存的內容沒有失效,那么返回給用戶的將是緩存中的信息。 



cache標簽的屬性說明: 

key - 標識緩存內容的關鍵詞。在指定的作用范圍內必須是唯一的。默認的key是被訪問頁面的URI和后面的請求字符串。 

你可以在同一個頁面中使用很多cache標簽而不指定他的key屬性,這種情況下系統使用該頁面的URI和后面的請求字符串,另外再自動給這些key增加一個索引值來區分這些緩存內容。但是不推薦采用這樣的方式。 

scope - 緩存發生作用的范圍,可以是application或者session 

time - 緩存內容的時間段,單位是秒,默認是3600秒,也就是一個小時,如果設定一個負值,那么這部分被緩存的內容將永遠不過期。 

duration - 指定緩存內容失效的時間,是相對time的另一個選擇,可以使用簡單日期格式或者符合USO-8601的日期格式。如:duration=''PT5M'' duration=''5s''等 

refresh - false 或者true。 

如果refresh屬性設置為true,不管其他的屬性是否符合條件,這部分被緩存的內容都將被更新,這給編程者一種選擇,決定什么時候必須刷新。 

mode - 如果編程者不希望被緩存的內容增加到給用戶的響應中,可以設置mode屬性為"silent" 

其它可用的屬性還包括:cron 、groups、language、refreshpolicyclass、refreshpolicyparam。 

上面的這些屬性可以單獨使用,也可以根據需要組合使用,下面的例子將講解這些常用屬性的使用方式。 



(二) Cache標簽實例分析: 

1. 最簡單的cache標簽用法 

使用默認的關鍵字來標識cache內容,超時時間是默認的3600秒 

<cache:cache> 

<% //自己的JSP代碼內容 %> 

</cache:cache> 



2. 用自己指定的字符串標識緩存內容,並且設定作用范圍為session。 

<cache:cache key="foobar" scope="session"> 

<% //自己的JSP代碼內容 %> 

</cache:cache> 



3.動態設定key值,使用自己指定的time屬性設定緩存內容的超時時間,使用動態refresh值決定是否強制內容刷新。 

因為OSCache使用key值來標識緩存內容,使用相同的key值將會被認為使用相同的的緩存內容,所以使用動態的key值可以自由的根據不同的角色、不同的要求決定使用不同的緩存內容。 

<cache:cache key="<%= product.getId() %>" time="1800" refresh="<%= needRefresh %>"> 

<% //自己的JSP代碼內容 %> 

</cache:cache> 



4. 設置time屬性為負數使緩存內容永不過期 

<cache:cache time="-1"> 

<% //自己的JSP代碼內容 %> 

</cache:cache> 



5. 使用duration屬性設置超期時間 

<cache:cache duration=''PT5M''> 

<% //自己的JSP代碼內容 %> 

</cache:cache> 



6. 使用mode屬性使被緩存的內容不加入給客戶的響應中 

<cache:cache mode=''silent''> 

<% //自己的JSP代碼內容 %> 

</cache:cache> 


四、緩存過濾器 CacheFilter 

用CashFilter實現頁面級緩存 

在OSCache組件中提供了一個CacheFilter用於實現頁面級的緩存,主要用於對web應用中的某些動態頁面進行緩存,尤其是那些需要生成pdf格式文件/報表、圖片文件等的頁面,不僅減少了數據庫的交互、減少數據庫服務器的壓力,而且對於減少web服務器的性能消耗有很顯著的效果。 

這種功能的實現是通過在web.xml中進行配置來決定緩存哪一個或者一組頁面,而且還可以設置緩存的相關屬性,這種基於配置文件的實現方式對於J2EE來說應該是一種標准的實現方式了。 

[注] 只有客戶訪問時返回http頭信息中代碼為200(也就是訪問已經成功)的頁面信息才能夠被緩存 


1. 緩存單個文件 

修改web.xml,增加如下內容,確定對/testContent.jsp頁面進行緩存。 

<filter> <filter-name>CacheFilter</filter-name> 

<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class> </filter> 

<filter-mapping> 

<filter-name>CacheFilter</filter-name> 

<!-對/testContent.jsp頁面內容進行緩存--> 

<url-pattern>/testContent.jsp</url-pattern> 

</filter-mapping> 



2. 緩存URL pattern 

修改web.xml,增加如下內容,確定對*.jsp頁面進行緩存。 

<filter> <filter-name>CacheFilter</filter-name> 

<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class> </filter> 

<filter-mapping> 

<filter-name>CacheFilter</filter-name> 

<!-對所有jsp頁面內容進行緩存--> 

<url-pattern>*.jsp</url-pattern> 

</filter-mapping> 



3. 自己設定緩存屬性 

在頁面級緩存的情況下,可以通過設置CacheFilter的初始屬性來決定緩存的一些特性:time屬性設置緩存的時間段,默認為3600秒,可以根據自己的需要只有的設置,而scope屬性設置,默認為application,可選項包括application、session 

<filter> <filter-name>CacheFilter</filter-name> 

<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class> <init-param> 

<param-name>time</param-name> 

<param-value>600</param-value> 

</init-param> 

<init-param> 

<param-name>scope</param-name> 

<param-value>session</param-value> 

</init-param> 

</filter> 

<filter-mapping> 

<filter-name>CacheFilter</filter-name> 

<!-對所有jsp頁面內容進行緩存--> 

<url-pattern>*.jsp</url-pattern> 

</filter-mapping> 



五、緩存對象 
一、對象緩存 

1、Cache操作類 
Java代碼  收藏代碼
   import java.util.Date;  
  
import com.opensymphony.oscache.base.NeedsRefreshException;  
  
import com.opensymphony.oscache.general.GeneralCacheAdministrator;  
  
public class BaseCache extends GeneralCacheAdministrator {       
  
    private int refreshPeriod; //過期時間(單位為秒);           
  
    private String keyPrefix; //關鍵字前綴字符;              
  
    private static final long serialVersionUID = -4397192926052141162L;          
  
    public BaseCache(String keyPrefix,int refreshPeriod){      
  
        super();      
  
        this.keyPrefix = keyPrefix;      
  
        this.refreshPeriod = refreshPeriod;      
  
    }      
  
    //添加被緩存的對象;      
  
    public void put(String key,Object value){      
  
        this.putInCache(this.keyPrefix+"_"+key,value);      
  
    }      
  
    //刪除被緩存的對象;      
  
    public void remove(String key){      
  
        this.flushEntry(this.keyPrefix+"_"+key);      
  
    }      
  
    //刪除所有被緩存的對象;      
  
    public void removeAll(Date date){      
  
        this.flushAll(date);      
  
    }             
  
    public void removeAll(){      
  
        this.flushAll();      
  
    }      
  
    //獲取被緩存的對象;      
  
    public Object get(String key) throws Exception{      
  
        try{      
  
            return this.getFromCache(this.keyPrefix+"_"+key,this.refreshPeriod);      
  
        } catch (NeedsRefreshException e) {      
  
            this.cancelUpdate(this.keyPrefix+"_"+key);      
  
            throw e;      
  
        }        
  
    }              
  
}     

2、Cache管理類 

Java代碼  收藏代碼
public class CacheManager {          
  
    private BaseCache newsCache;              
  
    private static CacheManager instance;      
  
    private static Object lock = new Object();             
  
    private CacheManager() {      
  
        //這個根據配置文件來,初始BaseCache而已;      
  
        newsCache = new BaseCache("news",120);           
  
    }              
  
    public static CacheManager getInstance(){      
  
        if (instance == null){      
  
            synchronized( lock ){      
  
                if (instance == null){      
  
                    instance = new CacheManager();      
  
                }      
  
            }      
  
        }      
  
        return instance;      
  
    }         
  
  
   
  
  
    public void removeAllNews() {      
  
        newsCache.removeAll();      
  
    }         
  
    public void putUser(User news) { newsCache.put(news.getId()+"",news);      }         
  
    public void removeUser(String newsID) {  newsCache.remove(newsID);       }         
  
    public User getUser(int newsID) {      
  
        try {      
  
            return (User) newsCache.get(newsID+"");      
  
        } catch (Exception e) {      
  
            System.out.println("getNews>>newsID["+newsID+"]>>"+e.getMessage());      
  
            User news = new User(newsID);      
  
            this.putUser(news);      
  
            return news;      
  
        }      
  
    }         
}  

3、對象Bean 

Java代碼  收藏代碼
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(System.currentTimeMillis());  
  
    }  
  
    public String toString() {  
  
       return "User info is : id=" + id + "  accessTime="  
  
              + accessTime.toString();  
  
    }  
  
    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;  
  
    }  
  
}  

4、測試類 

Java代碼  收藏代碼
public class TestObjectCache {  
  
    public static void main(String[] args) {  
  
       CacheManager cm=CacheManager.getInstance();  
  
         
  
       TestObjectCache test=new TestObjectCache();  
  
       test.print(cm);  
  
    }  
  
      
  
    public void print(CacheManager cm){  
  
       User user=null;  
  
       for (int i = 0; i < 1000; i++) {  
  
           user=cm.getUser(100);  
  
           System.out.println("<<"+i+">>: "+user);            
  
           if(i==10){  
  
              //刪除緩存id的對象  
  
              cm.removeUser(100+"");  
  
           }            
  
           if(i==20){  
  
              //刪除所有緩存的對象  
  
              cm.removeAllNews();  
  
           }            
  
           // 睡眠部分  
  
           try {  
  
              Thread.sleep(30000);  
  
           } catch (Exception e) {  
  
           }  
  
       }  
  
    }  
  
}  


CacheManager 類 

Java代碼  收藏代碼
public class CacheManager {  
  
    private BaseCache newsCache;  
  
    private static CacheManager instance;  
  
    private static Object lock = new Object();  
  
   
  
    private CacheManager() {  
  
       // 這個根據配置文件來,初始BaseCache而已;  
  
       newsCache = new BaseCache("hrms", 300);  
  
    }  
  
   
  
    public static CacheManager getInstance() {  
  
       if (instance == null) {  
  
           synchronized (lock) {  
  
              if (instance == null) {  
  
                  instance = new CacheManager();  
  
              }  
  
           }  
  
       }  
  
       return instance;  
  
    }  
  
   
  
    public void put(Object news,String key,String[] groups) {  
  
       newsCache.put(key, news,groups);  
  
    }  
  
    public void remove(String key) {  
  
       newsCache.remove(key);  
  
    }  
  
    public Object get(String key) {  
  
       try {  
  
           return newsCache.get(key);  
  
       } catch (Exception e) {  
  
           return null;  
  
       }  
  
    }  
  
    public void removeAll() {  
  
       newsCache.removeAll();  
  
    }     
  
    public void removeObjectByGroup(String group){  
  
       newsCache.removeObjectByGroup(group);  
  
    }  
  
}  


BaseCache 類增加的2個方法如下: 

    // 添加被緩存的對象; 

    public void put(String key, Object value,String[] groups) { 

       this.putInCache(this.keyPrefix + "_" + key, value,groups); 

    } 

    //刪除該組的緩存對象 

    public void removeObjectByGroup(String group){ 

       this.flushGroup(group); 

    } 

第六部分:小結及其引申 



緩存是在提升系統響應時常用的一種技術,在系統緩存上通常采用的是有頁面緩存、處理緩存和數據緩存這三種具體的類別,應該說這三種緩存在實現上還是稍有不同,盡管底層的緩存實現是一樣的。 

頁面緩存 

頁面緩存是指對頁面中的內容片斷進行緩存的方案。比如頁面中有一個部分是顯示欄目中的內容的,那么就可以緩存這個部分,在進行第二次請求的時候就直接從緩存中取出這部分的內容(其實就是這部分的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為了避免這個麻煩,采用的就是當數據一旦發生改變的時候就清除全部的查詢緩存,而不是只去清除相關的緩存,其實這里可以采用一種訂閱式的模型,呵呵,當然,也增加了框架的復雜度。 

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

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





補充部分: 

       在SSH項目應用中,可以以對象的形式來緩存展現給用戶的數據信息。對象的緩存要充分利用分組帶來的好處(可以分組刪除被緩存的對象),這樣在執行數據庫的CUD操作時,可以調用刪除相應組別的緩存對象。 

示例代碼: 

    private CacheManager cm; 

    

    private final static String CACHE_KEY_SUB="RetJobs"; 



    public JobAction() { 

       //獲取緩存管理對象 

       cm = CacheManager.getInstance(); 

    } 

         

查詢部分 

       page=(Page<RetJob>)(cm.get(CACHE_KEY_SUB+"_"+currentPage)); 

       if(page==null){ 

           //--------------------需要緩存對象部分----------------------- 

           page = retJobBaseModel.getJobs(currentPage, pageSize, statusCondition); 

           //------------------------------------------- 

           //緩存對象(含所屬分組信息) 

           cm.put(page, CACHE_KEY_SUB+"_"+currentPage,new String[]{CACHE_KEY_SUB}); 

       } 



CUD操作部分 

setCacheDisabled(CACHE_KEY_SUB); 



    private void setCacheDisabled(String group) { 

       //通過組別信息來刪除緩存的對象。 

       cm.removeObjectByGroup(group); 

    } 


----------------------------------------偶很華麗----------------------- 
其他幫助信息: 
參閱資料: 

[0]:http://www.opensymphony.com/oscache/ 

[1]:OSCache簡介 

[2]:OSCache分析 

[3]:OSCache——學習筆記 

[4]:應用OSCache提升J2EE系統運行性能 

[5]:[Java]用OSCache進行緩存對象 

[6]:osCache 配置說明 

[7]:緩存漫談 

轉:http://shijincheng0223.iteye.com/blog/1412128


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM