本文檔介紹了如何在
Portlet
應(yīng)用中使用
OSCache
進(jìn)行頁面內(nèi)容緩存和對(duì)象緩存,分析了
OSCache
的實(shí)現(xiàn)原理,并提出了一個(gè)用來緩存對(duì)象和頁面的簡單易用的方案。本文檔不涉及
OSCache
的安裝與配置的內(nèi)容,相關(guān)內(nèi)容請(qǐng)參考
OSCache
的
在線文檔
。
OSCache標(biāo)記庫由OpenSymphony設(shè)計(jì),它是一種開創(chuàng)性的緩存方案,它提供了在現(xiàn)有JSP頁面之內(nèi)實(shí)現(xiàn)內(nèi)存緩存的功能。OSCache是個(gè)一個(gè)被廣泛采用的高性能的J2EE緩存框架,OSCache還能應(yīng)用于任何Java應(yīng)用程序的普通的緩存解決方案。
OSCache有以下特點(diǎn):
l?????
緩存任何對(duì)象:你可以不受限制的緩存部分jsp頁面或HTTP請(qǐng)求,任何java對(duì)象都可以緩存。
l?????
擁有全面的API:OSCache API允許你通過編程的方式來控制所有的OSCache特性。
l?????
永久緩存:緩存能被配置寫入硬盤,因此允許在應(yīng)用服務(wù)器的多次生命周期間緩存創(chuàng)建開銷昂貴的數(shù)據(jù)。
l?????
支持集群:集群緩存數(shù)據(jù)能被單個(gè)的進(jìn)行參數(shù)配置,不需要修改代碼。
l?????
緩存過期:你可以有最大限度的控制緩存對(duì)象的過期,包括可插入式的刷新策略(如果默認(rèn)性能不能滿足需要時(shí))。
圖
3-1 OSCache
架構(gòu)概覽
Cache Factory
:該實(shí)體負(fù)責(zé)獲得
Cache Proxy
,兼有一些對(duì)
Cache Proxy
的管理功能。對(duì)應(yīng)到現(xiàn)在的
OSCache
實(shí)現(xiàn)中的類是:
GeneralCacheAdministrator
和
ServletCacheAdministrator
。
Cache Proxy
:該實(shí)體是
Cache Map
的代理,它主要負(fù)責(zé)從
Cache Map
中取得
/
存儲(chǔ)指定的緩存對(duì)象,如果緩存對(duì)象過期,那么就將緩存刷新,并向指定的監(jiān)聽者發(fā)送存
/
取事件。對(duì)應(yīng)到現(xiàn)在的
OSCache
實(shí)現(xiàn)中的類是:
Cache
和
ServletCache
。
Cache Map
:該實(shí)體存儲(chǔ)了所有的緩存實(shí)體,是一個(gè)
OSCache
專有的
Map
實(shí)現(xiàn),它能根據(jù)指定的算法清除緩存,以及將緩存持久化到磁盤中。對(duì)應(yīng)到現(xiàn)在的
OSCache
實(shí)現(xiàn)中的類是:
FIFOCache
,
LRUCache
和
UnlimitedCache
。
Listeners
:
OSCache
存
/
取事件的監(jiān)聽者實(shí)體。對(duì)應(yīng)到現(xiàn)在的
OSCache
實(shí)現(xiàn)中的類是:
CacheEntryEventListener
和
CacheMapAccessEventListener
。
Cache Entry
:表示緩存對(duì)象的包裝實(shí)體,它包裝了緩存對(duì)象和刷新策略。對(duì)應(yīng)到現(xiàn)在的
OSCache
實(shí)現(xiàn)中的類是:
CacheEntry
。
一個(gè)典型的“緩存對(duì)象”場景是:
應(yīng)用調(diào)用
Cache Factory
獲得
Cache Proxy
,然后應(yīng)用將要緩存的對(duì)象以及刷新策略通過
Cache Proxy
存儲(chǔ)到
Cache Map
中,并通知各個(gè)
Listener
。
一個(gè)典型的“取得緩存對(duì)象”的場景是:
應(yīng)用調(diào)用
Cache Factory
獲得
Cache Proxy
,然后給
Cache Proxy
的相應(yīng)方法傳入要獲得的緩存對(duì)象的
key
,
Cache Proxy
會(huì)根據(jù)指定的刷新策略判斷緩存是否過期,如果緩存沒有過期,則返回緩存對(duì)象,如果緩存過期,則刷新緩存,并向應(yīng)用層拋出需要刷新的異常(
NeedsRefreshException
),應(yīng)用如果收到此異常,將重新計(jì)算內(nèi)容并將內(nèi)容緩存。
?
OSCache
現(xiàn)有的緩存刷新策略(超過指定時(shí)間后自動(dòng)過期,超過指定日期后自動(dòng)過期,按照克龍表達(dá)式的設(shè)定自動(dòng)過期)不能滿足需求。現(xiàn)有應(yīng)用要求:當(dāng)數(shù)據(jù)源的部分內(nèi)容更新后,能夠使相關(guān)緩存過期,展現(xiàn)頁面從數(shù)據(jù)源取得更新的內(nèi)容顯示。
該方案為下列場景提供了支持:
1.
緩存整個(gè)
Response
,能夠定制刷新指定的
Response
。
2.
緩存
JSP
頁面內(nèi)容,能夠定制刷新指定的緩存內(nèi)容。
3.
緩存對(duì)象,能夠定制刷新指定的緩存對(duì)象。
在
Web
應(yīng)用的
web.xml
中添加下面的內(nèi)容:
<
filter>
?????????????
<
filter-name>CacheFilter</filter-name>
?????????????
<
filter-class>
???????????????????? com.***.portal.oscache.***CacheFilter
?????????????
</
filter-class>
?????????????
<
init-param>
????????????????????
<
param-name>time</param-name>
????????????????????
<
param-value>-1</param-value>
?????????????
</
init-param>
?????????????
<
init-param>
????????????????????
<
param-name>scope</param-name>
定制這個(gè)
fileter
緩存的
response
的組
|
????????????????????
<
param-value>application</param-value>
?????????????
</
init-param>
?????????????
<init-param>
???????????????????? <param-name>groups</param-name>
???????????????????? <param-value>
landy
</param-value>
????????????? </init-param>
??????
</
filter>
<
filter-mapping>
?????????????
<
filter-name>CacheFilter</filter-name>
?????????????
<
url-pattern>/
landy
</
url-pattern>
??????
</
filter-mapping>
|
注意:
為了在部分?jǐn)?shù)據(jù)更新時(shí)只刷新部分
Response
,
***CacheFilter
比
OSCache
提供的
CacheFitler
增加了一個(gè)可配置的參數(shù):“
groups
”,部署者可以通過這個(gè)參數(shù)配置這個(gè)
filter
所映射的
URLS
的組(通常同一個(gè)組的
URL
會(huì)從同時(shí)更新的數(shù)據(jù)源取數(shù)據(jù)),這樣當(dāng)數(shù)據(jù)源某部分更新之后,我們就可以刷新從這部分?jǐn)?shù)據(jù)源取數(shù)據(jù)的
URLs
。該配置項(xiàng)支持配置多個(gè)組,以逗號(hào)作為分隔符,如:“
group1,group2
”。
其他的配置項(xiàng)說明請(qǐng)參考
OSCache
在線文檔的
CacheFilter
配置部分
。
OSCache
提供的
CacheFilter
能夠緩存
Response
,但不能供應(yīng)用選擇性的刷新某些
Response
,而
***CacheFilter
就能支持這一特性。
您可以按照以下的方式刷新某一組(
Filter
初始化參數(shù)中
groups
參數(shù)配置的內(nèi)容)的
Responses:
ServletCacheAdministrator admin = null;
Filter
初始化參數(shù)中
scope
參數(shù)配置的內(nèi)容
?
|
admin = ServletCacheAdministrator.getInstance(config
?????????????????????????? .getServletContext());
Filter
初始化參數(shù)中
groups
參數(shù)配置的內(nèi)容
|
Cache cache = admin.getCache(httpRequest, cacheScope);
cache. flushGroup(group);
|
這種方案僅適用于普通的
web
應(yīng)用,不適用于
Portlets
應(yīng)用,因?yàn)樵?/span>
Portlets
應(yīng)用中,每個(gè)
Portlet
都是頁面上一個(gè)可插拔的組件,如果被緩存的
Response
代表的頁面中某個(gè)
Portlet
被刪除了,那么這個(gè)頁面產(chǎn)生的
Response
就會(huì)不一樣,而這時(shí)應(yīng)用卻無法刷新緩存的
Response
。
可以在
JSP
頁面中將要緩存的內(nèi)容置于
<cache></cache>
標(biāo)簽之間,當(dāng)更新數(shù)據(jù)源的事件產(chǎn)生時(shí),在處理事件的方法中加入如下代碼即可:
***OSCacheUtil.getInstance().flushGroup("group1");
|
我要緩存一個(gè)從數(shù)據(jù)源的
A
表取數(shù)據(jù)的
JSP
內(nèi)容段,如下表所示:
<oscache:cache key="foobar" scope="application" time="-1" groups="group1" >
//business code
Select * from table A and Display
</oscache:cache>
|
數(shù)據(jù)源更新了,在處理數(shù)據(jù)更新事件的代碼中,我加入下表的代碼:
***OSCacheUtil.getInstance().flushGroup("group1");
|
這樣就可以刷新緩存的
group1
組的數(shù)據(jù)了。
本方案在滿足了
4.1
描述的需求的條件下,僅支持選擇性的刷新存儲(chǔ)在
application
域(
cache
標(biāo)簽中
scope
屬性配置為
application
)的緩存。為什么不支持選擇性的刷新
session
域的緩存呢?是因?yàn)閿?shù)據(jù)更新的事件產(chǎn)生是隨機(jī)的,當(dāng)數(shù)據(jù)更新事件發(fā)生時(shí),我們無法得到
web
服務(wù)器中的每個(gè)
session
,所以不能支持選擇性的刷新
session
域的緩存。
可以在
web
應(yīng)用的業(yè)務(wù)處理邏輯中將要緩存的對(duì)象采用如下的方式將對(duì)象緩存到
application
域中:
***OSCacheUtil.getInstance().putInCache(key, content, new String[]{“group1”});
|
當(dāng)更新數(shù)據(jù)源的事件產(chǎn)生時(shí),在處理事件的方法中加入如下代碼即可:
***OSCacheUtil.getInstance().flushGroup("group1");
|
同
4.5.2
一致。
?
包括
***CacheFilter
和
***OSCacheUtil
。
用例
src
:
用例
ear
:
參考資料:
[1]
http:/www.opensymphony.com/oscache/