OSCache使用介紹
一.OSCache簡介 OSCache是OpenSymphony這個開源項目眾多Projects中的一個。他是一個高效的J2EE緩存框架,能夠很好的解決動態(tài)網(wǎng)站速度的問題。下面來 看下OSCache解決了動態(tài)網(wǎng)站的哪些令人郁悶的問題。 1.緩存動態(tài)內(nèi)容:其實我們的動態(tài)網(wǎng)頁上一般只有一部分是動態(tài)的(表頭,表尾一般是不變的),如果我們緩存整個網(wǎng)頁顯然不成,因為有部分是 隨著請求有可能變的。OSCache提供的方式是允許我們只緩存一部分網(wǎng)頁。 2.緩存2進制內(nèi)容:產(chǎn)生的圖片和PDF文件在服務(wù)器加載的時候非常的耗時。OSCache解決這個問題是通過一個Servlet2.3的緩存過濾功能,然后能 夠緩存任意的URI(比如一個完整的頁面或者是一個產(chǎn)生的圖片/PDF文件) 3.容錯:有這種情況或許我們會遇到,就是當(dāng)一個動態(tài)的網(wǎng)頁出現(xiàn)錯誤。即便我們的頁面有95%都加載完畢,但就是由于這個錯誤,整個頁面就會 返回錯誤的提示或頁面。OSCache允許我們提供出現(xiàn)錯誤時的緩存內(nèi)容,如果出現(xiàn)就適時的提示出來了。 除了上面的這些Servlet的特征外,OSCache完全可以充當(dāng)任何一個java程序的緩存方案。OSCache 的一般特征如下: 1.緩存任意對象:可以不受限制的緩存JSP的一部分或是Http請求,任何的Java對象都可以被緩存。 2.全面的API:通過API可以完完全全的控制OSCache的任何特性。 3.持久緩存:我們可以把認(rèn)為重要的數(shù)據(jù)緩存到硬盤上。 4.支持集群:集群緩存數(shù)據(jù)能被單個的進行參數(shù)配置,不需要修改代碼。 5.緩存記錄的過期:你可以有最大限度的控制緩存對象的過期,包括可插入式的刷新策略(如果默認(rèn)性能不需要時)。 二.OSCache運行環(huán)境 如果用到OSCache Tag Library的話,需要Servlet2.3和JSP1.2的支持。如果是直接用OSCache API的話那么就不需要Servlet容器的支持。 目前可以正常運行的Web容器: 1.OrionServer(版本1.4.0和更高) 2.JRun(3.0或更好) 3.WebLogic(8.1或以上) 4.Websphere(5.0或以上) 5.Resin(1.2.3或以上) 6.TomCat(4.0或以上) 7.iPlanet(6.0或以上) 用到緩存過濾需要Servlet2.3支持.目前知道的可以個工作在OrionServer,WebLogic,Tomcat上. OSCache需要Java的版本至少是java 1.4. 三.OSCache的安裝 1.解壓oscache-2.4.1-full后發(fā)現(xiàn)他下面有如下文件: 2.把oscache-2.4.1.jar放到/WEB-INF/lib下. 3.要確保commons-logging.jar也在環(huán)境變量中.一般情況下他也放在/WEB-INF/lib下. 4. 把/etc/oscache.properties放入/WEB-INF/classes下.如果用的Eclipse的話,建議新建一個 Source Folder比如叫Src_Config,然后就這個OSCache的屬性文件放在其中.通過修改這個OSCache的配置文件可以改變文件緩存的磁盤路徑,配置持久偵聽等等. 5.把etc/META-INF/oscache.tld也放在/WEB-INF/classes下. 你的目錄結(jié)構(gòu)如下: 四.OSCache應(yīng)用學(xué)習(xí) 1.JSP的應(yīng)用 要是想應(yīng)用OSCache的標(biāo)簽,我們必須先要引入進來.方式有兩種. 其一.在web.xml中加入: <taglib> <taglib-uri>oscache</taglib-uri> <taglib-location>/WEB-INF/classes/oscache.tld</taglib-location> </taglib> 然后我們在JSp中就可以<%@ taglib uri="oscache" prefix="os"%>這樣來引用了. 其二,直接引用.直接在JSp中加入OSCache的標(biāo)簽庫引用 <%@ taglib uri="/WEB- INF/classes/oscache.tld" prefix="os"%>.如果要進入官方的標(biāo)簽庫的話也行.& lt;%@ taglib uri="http://www.opensymphony.com/oscache" prefix="cache" %& gt;這樣就不用再把oscache.tld放在/WEB-INF/classes下了. 目前OSCache有5個標(biāo)簽.他們是cache, usecached, flush, addgroup, addgroups.下面我們來分別介紹一下他們的屬性和用法. <cache></cache> 他是OSCache中最主要的標(biāo)簽了.括起來的內(nèi)容將根據(jù)屬性的設(shè)置來緩存起來.第一次執(zhí)行的時候,OSCache會把cache標(biāo)簽中的JSp執(zhí)行并且緩存起來,以后再執(zhí)行的話,他會首先判斷緩存的內(nèi)容是否過期,如果過期那么會從新執(zhí)行并緩存.否則就直接從緩存中讀取.判定過期的條件如下: i.緩存的內(nèi)容超過了屬性time所指定的時間. ii.不符合cron設(shè)置的時間間隔. iii.如果scope指定的范圍刷新的話,則認(rèn)為過期了.如Session過期. 屬性如下: key : 緩存的Key,可以是任何的字符,用來尋找緩存的內(nèi)容用的.可以理解成HashMap中的Key.不能把2個要緩存的東東定義成一個名字,那樣后一個會覆蓋前一個的內(nèi)容.默認(rèn)情況,如果不指定Key的話,OSCache也會自動生成一個Key,規(guī)則是請求的URI+當(dāng)前頁面的Query String. scope : 緩存的范圍.有2個, application和session.默認(rèn)值是application. time : 緩存內(nèi)容的時間.以秒為單位,默認(rèn)是3600秒.到了指定的時間,就會刷新緩存內(nèi)容.如果指定一個負(fù)數(shù)的話,意味著永遠(yuǎn)不會過期. duration : 也是用來指定緩存內(nèi)容的時間,它和time屬性只能是2選1,它的特點是可以用Simple Data Format 或者是ISO-8601進行日期格式化. cron : 用萬年歷的形式指定緩存內(nèi)容何時過期的.它應(yīng)用的Unix的萬年歷形式,如("0 * * * *") refresh : 是個Boolean值,如果是True的話,則不管前面提到的過期檢查,都刷新.默認(rèn)情況是false. mode : 設(shè)置這項為”silent”將防止把括起來的內(nèi)容輸出.這在你預(yù)加載緩存內(nèi)容而不愿顯示給用戶看到時很有用. groups : 可以提供一個以逗號分割的組名稱.如group="A, B".這將允許你以組的名義來操作他們,分組非常有用,比如你要緩存的內(nèi)容正好需要另外一個應(yīng)用程序的一部分或數(shù)據(jù),當(dāng)依賴的發(fā)生了改變,正好聯(lián)動的可以使很多的組過期,進而使與組發(fā)生關(guān)聯(lián)的緩存內(nèi)容得到更新. language : 設(shè)置編碼方式. refreshpolicyclass:指定自定義的類來處理緩存的內(nèi)容什么時候過期.這個類需要從 refreshpolicyparam com.opensymphony.oscache.web.WebEntryRefreshPolicy繼承. refreshpolicyparam : 它和上面的是聯(lián)合使用的.是給refreshpolicyclass傳任意的參數(shù)的.指定這項的話,就必須有refreshpolicyclass,否則就不起作用. 屬性就這么多了,下面舉幾個應(yīng)用的例子: <os:cache key="<%=myKey%>" time="1800" refresh="<%=needRefresh%>"> <!--這里是要緩存的內(nèi)容--> </os:cache> 這里將myKey標(biāo)識的緩存內(nèi)容保持30分鐘,到期自動刷新.如果needRefresh為true也會刷新(適合于更新內(nèi)容的即時刷新). <os:cache key="<%=myKey%>" cron="0 2 * * *" refresh="<%=needRefresh%>"> <!--這里是要緩存的內(nèi)容--> </os:cache> 將myKey標(biāo)識的緩存內(nèi)容在每天的凌晨2時自動刷新.如果needRefresh為true也會刷新(適合于更新內(nèi)容的即時刷新). 舉到了這個例子,我不得不把cron表達式多說幾句.首先這五顆星的位置代表 分,小時,一個月中的天,月,一周中的天 分: 無疑問0~59. 小時 : 無疑問 0~23. 天(月) : 1~31 月 : 1~12,用英文全稱也可以.如January, April 天(周): 0~6(0代表Sunday; 1代表Monday… 6代表Saturday) 舉個例子,比如我們想讓緩存的內(nèi)容在4月的晚上11:45分過期.我們可以這樣來寫 "45 23 * April *". <usecached /> 需要放在cache標(biāo)簽中嵌套使用(一般配合try..catch使用)告訴他的上級標(biāo)簽是否應(yīng)用緩存的譯本. 則出現(xiàn)異常時將會替換包括上級標(biāo)簽在內(nèi)的所有內(nèi)容(提示:Missing cached content). use="true|false" : 是否應(yīng)用的標(biāo)記. 默認(rèn)為True.一般省略. 應(yīng)用例子: <os:cache> ..內(nèi)容.. <% try {%> ......其它內(nèi)容 <%}catch (Exception e) {%> Inside catch: <os:usecached use="<%=isUsed%>"/> YES <% } %> </os:cache> 則出現(xiàn)異常時的頁面輸出有兩種: 1>. isUsed=false ..內(nèi)容.. ......其它內(nèi)容 Inside catch: YES 2>. isUsed=true Missing cached content <flush /> 這個標(biāo)簽是用于在運行時狀態(tài)下刷新緩存的.這個標(biāo)簽非常有用,因為它可以放在Web程序的管理部分使管理員可以決定何時刷新緩存. 屬性如下: scope : 刷新的范圍.3個值, "application", "session" and null .null表示刷新所有. Key : 和scope聯(lián)合使用,刷新指定范圍的指定緩存.如果不指定scope則key無效. group : 和scope聯(lián)合使用, 刷新指定范圍的指定組中的緩存. 不指定scope無效. Pattern :任何包含了pattren指定的字符串的緩存都被更新.它也是和scope連用.但是現(xiàn)在官方不贊成再用這個屬性了.用group完全可以取代這個.便于管理. language : 設(shè)置編碼方式 舉幾個應(yīng)用的例子: 刷新整個application. <os:flush scope="application" /> 刷新session中的foobar這個緩存. <os:flush scope="session" key="foobar" /> 在application 中刷新所有currencyData 組中的緩存 <os:flush scope="application" group="currencyData" /> <addgroup /> 這個標(biāo)簽也是必須嵌套在cache標(biāo)簽中的.把緩存的東東放入到指定的組中.這樣就可以以組來刷新指定的內(nèi)容了. 屬性只有g(shù)roup來指定名字的.例子如下: 把test1加入到group1和group2中 <os:cache key="test1"> < os:addgroup group="group1" /> ... some jsp content ... < os:addgroup group="group2" /> ... some more jsp content ... </ os:cache> <addgroups /> (2.3及以后的版本中新加的) 同上面的功能相同,只不過可以不用一個一個加group了.例子如下: < os:cache key="test1"> ... some jsp content ... < os:addgroups groups="group1,group2" /> ... some jsp content ... </ os:cache> 2.API的應(yīng)用 在實際應(yīng)用中除了JSP標(biāo)簽庫和CacheFilter(下面介紹)外,還可以使用OSCache提供的Java API .下面我來介紹一個實用的 Java類 ,使用GeneralCacheAdministrator來建立,刷新和管理緩存. GeneralCacheAdministrator 可以被實例化,里面有很多的實用方法.此外它還管理加載cache.properties并且根據(jù)這個屬性文件創(chuàng)建一個緩存實例.因此你最好使用單例模式來創(chuàng)建GeneralCacheAdministrator實例. 主要用到的GeneralCacheAdministrator的方法有 public Object getFromCache(String key) throws NeedsRefreshException; -- 從緩存中獲取一個key標(biāo)識的對象. public Object getFromCache(String key, int refreshPeriod) throws NeedsRefreshException ; -- 從緩存中獲取一個key標(biāo)識的對象. refreshPeriod刷新周期,標(biāo)識此對象在緩存中保存的時間(單位:秒) public void putInCache(String key, Object content) -- 存儲一個由Key標(biāo)識的緩存對象. public void putInCache(String key, Object content, String[] groups) -- 存儲一個由Key標(biāo)識的屬于groups中所有成員的緩存對象. public void flushEntry(String key) -- 更新一個Key標(biāo)識的緩存對象. public void flushGroup(String group) --更新一組屬于groupr標(biāo)識的所有緩存對象. public void flushAll() -- 更新所有緩存. public void cancelUpdate(String key) --- 取消更新 只用于在處理捕獲的NeedsRefreshException異常并嘗試生成新緩存內(nèi)容失效的時候. public void removeEntry(String key) ---從緩中移除一個key標(biāo)識的對象 public void clear() --- 清除所有緩存 官方的使用例子: ///采取補救措施的典型方案 String myKey = "myKey"; String myValue; int myRefreshPeriod = 1000; //刷新周期1000秒 try { //從Cache中獲得 要做類型轉(zhuǎn)換 myValue = (String) admin.getFromCache(myKey, myRefreshPeriod); } catch (NeedsRefreshException nre) { try { // Cache中沒有則從庫獲得數(shù)據(jù). myValue = "This is the content retrieved."; // 存放在Cache中 鍵值myKey admin.putInCache(myKey, myValue); } catch (Exception ex) { // 嘗試恢復(fù)Cache中的內(nèi)容 myValue = (String) nre.getCacheContent(); // 如果Cache中的內(nèi)容沒有復(fù)原 則用這個終級方法 admin.cancelUpdate(myKey); //取消對myKey的更新 即類似數(shù)據(jù)回滾 } } ///不采取補救措施的典型方案 String myKey = "myKey"; String myValue; int myRefreshPeriod = 1000; try { //從Cache中獲得 要做類型轉(zhuǎn)換 myValue = (String) admin.getFromCache(myKey, myRefreshPeriod); } catch (NeedsRefreshException nre) { try { // Cache中沒有則從庫獲得數(shù)據(jù). myValue = "This is the content retrieved."; // 存放在Cache中 鍵值myKey admin.putInCache(myKey, myValue); updated = true; } finally { if (!updated) { // 如果Cache中的內(nèi)容更新出現(xiàn)異常 則用這個終級方法 admin.cancelUpdate(myKey); //取消對myKey的更新 即類似數(shù)據(jù)回滾 } } } 注意: 如果一個NeedsRefreshException出現(xiàn) 必須調(diào)用admin.putInCache或甚至admin.cancelUpdate來避免死鎖情況發(fā)生. 3.CacheFilter的應(yīng)用 OScache可以是你很輕易的緩存網(wǎng)站中全部頁面,甚至是那些2進制文件.從2.4版本開始你可以在運行期設(shè)置和覆蓋CacheFilter的初始化參數(shù).注意,只有返回狀態(tài)為200的頁面才會緩存. (HttpServletResponse.SC_OK). 配置CacheFilter,在Web.xml中加入如下: <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> <url-pattern>*.jsp</url-pattern> </filter-mapping> 這個例子將在session范圍緩存所有JSp10分鐘.默認(rèn)情況scope為application,時間為1小時. 如果ICacheKeyProvider不設(shè)置的話,這個CacheFilter將使用(URI+QueryString)作為緩存Key. 你可以使用下列的初始化參數(shù)來設(shè)置CacheFilter: Parameter: time 設(shè)置緩存時間,默認(rèn)是1個小時.可以設(shè)置為-1(不確定).這樣他就不會過期了.除非你明確刷新它(前面說到的refresh =”true”).或者是更改這個刷新的策略. Parameter: scope 同cache的scope. 也是有application(default)和session Parameter: cron (NEW! Since 2.3) 同cache的scope.設(shè)置過期 Parameter: fragment (NEW! Since 2.2) 作用不太清除,用默認(rèn)即可. Parameter: nocache (NEW! Since 2.2) 定義那些頁面不需要緩存.”off”---緩存所有;”sessionIdInURL”---如果session中包括這URL的則不緩存這個頁面 Parameter: lastModified (NEW! Since 2.2) 定義是否把Header發(fā)送到Response中. ”off”----不發(fā)送,即便它設(shè)置在過濾鏈中. “on”----如果在過濾鏈中則發(fā)送. “inital”(default)----最后更改的信息將基于當(dāng)前時間被設(shè)置 Parameter: max-age (NEW! Since 2.3.1) 設(shè)置在瀏覽器中緩存的最大時間.在設(shè)置的期間,不再向服務(wù)器請求,而是從自己的緩存中查找頁面.默認(rèn)是60秒. Parameter: expires (NEW! Since 2.2) 定義過期header發(fā)送到Response中的時間. “off”----不發(fā)送. “on”(default)---如果在過濾鏈中則發(fā)送.并且time這個過期信息將基于時間參數(shù)和頁面內(nèi)容的創(chuàng)建時間初始化. Parameter: ICacheKeyProvider (NEW! Since 2.2) 指定實現(xiàn)ICacheKeyProvider接口的類. Parameter: ICacheGroupsProvider (NEW! Since 2.2) 指定實現(xiàn)ICacheGroupsProvider接口的類 Parameter: EntryRefreshPolicy (New! Since 2.3) 指定實現(xiàn)EntryRefreshPolicy接口的類. Parameter: disableCacheOnMethods (New! Since 2.4) 指定請求方式不進行緩存.默認(rèn)Null,對所有的請求方式都緩存.例如: <init-param> <param-name>disableCacheOnMethods</param-name> <param-value>POST,PUT,DELETE</param-value> </init-param> Parameter: oscache-properties-file (New! Since 2.4) 通過指定OSCache的屬性文件,開發(fā)者就能運行多個CacheFilter 4.OSCache的屬性文件.(oscache.properties) cache.memory 值為true或false.默認(rèn)為true.如果設(shè)置為false那么緩存到數(shù)據(jù)庫或硬盤中.似乎有點傻,所以我們一般不改此項. cache.capacity 緩存元素的個數(shù).默認(rèn)是沒有限制的. cache.algorithm 緩存的算法.注意要是指定算法的話,必須把上面的緩存?zhèn)€數(shù)指定.這里支持三種算法. com.opensymphony.oscache.base.algorithm.LRUCache – 最后最近使用 com.opensymphony.oscache.base.algorithm.FIFOCache – 先進先出 com.opensymphony.oscache.base.algorithm.UnlimitedCache – 無限緩存 cache.blocking 是否同步化。true 或者 false。一般設(shè)為true,避免讀取臟數(shù)據(jù)。 cache.unlimited.disk 指定硬盤緩存是否要作限制。默認(rèn)值為false。false的狀況下,disk cache capacity 將和cache.capacity的值相同。 cache.persistence.class 指定類是被持久化的類。class必須實現(xiàn)PersistenceListener接口。 作為硬盤持久,可以實現(xiàn) com.opensymphony.oscache.plugins.diskpersistence.HashDiskPersistenceListener 接口。 它把class的toString()輸出的hash值作為文件的名稱。如果你要把文件名易讀(自己設(shè)定),DiskPersistenceListener 的父類也 能使用,但其可能有非法字符或者過長的名字。 注意:HashDiskPersistenceListener 和 DiskPersistenceListener 需要設(shè)定硬盤路徑:cache.path cache.path 指定硬盤緩存的路徑。目錄如果不存在將被建立。同時注意oscache應(yīng)該要有權(quán)限寫文件系統(tǒng)。 cache.path=c:\\myapp\\cache or *ix: cache.path=/opt/myapp/cache cache.persistence.overflow.only (NEW! Since 2.1) 指定是否只有在內(nèi)存不足的情況下才使用硬盤緩存。 默認(rèn)值false。但推薦是true如果內(nèi)存cache被允許的話。這個屬性徹底的改變了cache的行為,使得persisted cache 和memory完全不同。 cache.event.listeners 用逗號分離的class名列表。每個class必須實現(xiàn)以下接口之一,或者幾個 CacheEntryEventListener:接收 cache add/update/flush and remove事件 CacheMapAccessEventListener :接收cache 訪問事件。這個可以讓你跟蹤cache怎么工作。 默認(rèn)是不配置任何class的。當(dāng)然你可以使用一下的 class: com.opensymphony.oscache.plugins.clustersupport.BroadcastingCacheEventListener -分布式的(此處被屏蔽)??梢詮V播到局域網(wǎng)內(nèi)的其他cache實例。 com.opensymphony.oscache.extra.CacheEntryEventListenerImpl -一個簡單的(此處被屏蔽)。在cache的生命周期中記錄count of 所有entry的事件。 com.opensymphony.oscache.extra.CacheMapAccessEventListenerImpl -記錄 count of cache map events(cache hits,misses and state hits). cache.key 設(shè)置ServletCacheAdministrator使用的Key.在代碼中如果需要用到的話,可以通過com.opensymphony.oscache.web.ServletCacheAdministrator.DEFAULT_CACHE_KEY得到. cache.use.host.domain.in.key 如果你的服務(wù)器是被配置到多臺主機上的話,你或許想加上一個主機的名字在它生成的緩存Key上.true的話會加上.默認(rèn)值是false. 附加的屬性: cache.cluster.multicast.ip, cache.cluster.properties 5.小結(jié): OSCache的使用主要有4種: POJO 緩存 HTTP Response 緩存 JSP Tag Library 緩存 O/R Data Access 緩存 1)、POJO 緩存 這種方式的緩存直接調(diào)用OSCache的API進行,主要用于處理頁面內(nèi)容會根據(jù)參數(shù)動態(tài)改變,可以將參數(shù)設(shè)置為key值來保存數(shù)據(jù): 首先,聲明成員變量: // OSCache Adminitrator instance private static GeneralCacheAdministrator cacheAdmin = null; 其次,進行初始化: public RingArtistAction() { cacheAdmin = new GeneralCacheAdministrator(); } 將POJO進行緩存: // Cache data key and refresh period String key = sex + ":" + place; int refreshPeriod = Constants.getIntegerValue(Constants.OSCACHE_REFRESH_PERIOD).intValue(); try { // Get from the cache artists = (Map) cacheAdmin.getFromCache(key, refreshPeriod); } catch (NeedsRefreshException nre) { try { // Get the value (probably from the database) int count = getArtistCount(sex, place, errors); artists = getArtistData(sex, place, count, errors); // Store in the cache cacheAdmin.putInCache(key, artists); } catch (Exception ex) { // We have the current content if we want fail-over. artists = (Map) nre.getCacheContent(); // It is essential that cancelUpdate is called if the // cached content is not rebuilt cacheAdmin.cancelUpdate(key); ex.printStackTrace(); } } 2)、HTTP Response 緩存 這種方式的緩存用來處理整個頁面的內(nèi)容固定,不會根據(jù)參數(shù)動態(tài)改變: 首先在web.xml中配置CacheFilter: <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>86400</param-value> </init-param> <init-param> <param-name>scope</param-name> <param-value>application</param-value> </init-param> </filter> 將所有需要緩存的頁面加入filter-mapping: <filter-mapping> <filter-name>Set Character Encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 注意,只有返回狀態(tài)為200(HttpServletResponse.SC_OK)的內(nèi)容才會被緩存 3)、JSP Tag 緩存 JSP Tag緩存主要用于緩存JSP頁面的局部內(nèi)容: <cache:cache key="especialcategory" cron="* 5 * * *"> <jsp:include page="/ringcategory.do" flush="true" > <jsp:param name="ringType" value="1"/> </jsp:include> </cache:cache> 4)、O/R Data Access 緩存 請閱讀參考資料的內(nèi)容獲取詳情。 |