有許多頁面的一部分或者這個頁面是很少更新的,他們通常是由外部文件來生成這個部分。所以我們可以把這部分內(nèi)容cache住,當有新的請求時,我們就responsecache,這樣可以減少服務器的負擔,還可以提高性能。其中oscache已經(jīng)可以實現(xiàn)頁面的cache和頁面部分cache。oscache使用jsptags來實現(xiàn)局部cache的。拿到Tapestry中肯定是行不通的。在同事的提醒下,想到寫這個Tapestry的cache組件來達到重用的目的。
說干就干,先在頭腦中想好要怎樣使用cache(頁面上的布局)。ok。 我想好了。
<span jwcid="@Cache" cacheProvider="ognl:cacheProvider" updateCondition="ognl:needUpdate">
//Cache body, which is the content you want to cache.
</span>
這里有2個參數(shù),updateCondition 當為true時,我們就繞過cache, cacheProvider我把他定義為一個接口,這樣用戶可以把cache存在任何地方。而且提供這樣的一個接口,用戶可以更好的操作cache。先看看jwc對cache組件的定義。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE component-specification PUBLIC
"-//Apache Software Foundation//Tapestry Specification 4.0//EN"
"><component-specificationallow-body="yes" allow-informal-parameters="no"class="com.live.spaces.dengyin2000.tapestry.tfancomponents.components.Cache">
<description>
Cache component, this component can inclue any content as its body, and cache its body.
This is useful in rarely updated content.
</description>
<parameter name="updateCondition" required="no" default-value="false">
<description>
The flag that need to refresh cache, it would casue tapestry render not use the cache.
</description>
</parameter>
<parameter name="cacheProvider" required="yes">
<description>
You need to provider an cache provider to store its body content. for some simply use.
Please see @com.live.spaces.dengyin2000.tapestry.tfancomponents.components.SimpleHtmlSourceCacheProvider
</description>
</parameter>
</component-specification>下面的是ICacheProvider接口
public interface ICacheProvider {
/**
*
* @param cacheKey
* @param cacheContent
*/
public void storeCache(String cacheKey, String cacheContent);
/**
*
* @param cacheKey
* @return
*/
public String getCacheContent(String cacheKey);
/**
* This method provider to user, so that user can controll cache manaully.
* @param cacheKey
*/
public void removeCache(String cacheKey);
/**
* This method provider to user, so that user can controll cache manaully.
* Clear all caches
*
*/
public void reset();
}ok。 再來看看Cache組件的代碼。
public abstract class Cache extends AbstractComponent {
protected static final Log logger = LogFactory.getLog(Cache.class);
public abstract boolean getUpdateCondition();
public abstract ICacheProvider getCacheProvider();
@Override
protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle) {
if (getUpdateCondition()){
renderComponentWithCache(writer, cycle);
}else{
if (getCacheProvider().getCacheContent(this.getIdPath()) != null){
//response cache html content.
writer.printRaw(getCacheProvider().getCacheContent(this.getIdPath()));
}else{
renderComponentWithCache(writer, cycle);
}
}}
private void renderComponentWithCache(IMarkupWriter writer, IRequestCycle cycle) {logger.debug("We need to refresh cache now.");
CacheWriterWrapper cacheWrapper = new CacheWriterWrapper();
super.renderBody(buildCacheMarkupWriter(cacheWrapper.getPrintWriter(), writer), cycle);
String cacheContent = cacheWrapper.getCacheContent();
logger.debug("fetched cache content, ready to put it into cache.");getCacheProvider().storeCache(this.getIdPath(), cacheContent);
// response html content.
writer.printRaw(cacheContent);
}
private IMarkupWriter buildCacheMarkupWriter(PrintWriter writer, IMarkupWriter sourceWriter){
returnthis.getPage().getRequestCycle().getInfrastructure().getMarkupWriterSource().newMarkupWriter(writer,new ContentType(sourceWriter.getContentType()));
}
class CacheWriterWrapper{
private StringWriter sw;
private PrintWriter pw;
public CacheWriterWrapper() {
sw = new StringWriter();
pw = new PrintWriter(sw);
}public String getCacheContent(){
return sw.getBuffer().toString();
}
public PrintWriter getPrintWriter(){
return pw;
}
}
}主要是得到cache組件body的內(nèi)容,然后把body的內(nèi)容cache住,下次的話就response Cache的內(nèi)容。 其實也是滿簡單的。
我自己還寫了一個簡單CacheProvider。
public class SimpleHtmlSourceCacheProvider implements ICacheProvider {
private Map<String, String> cache = new HashMap<String, String>();
public String getCacheContent(String cacheKey) {
return cache.get(cacheKey);
}public void storeCache(String cacheKey, String cacheContent) {
cache.put(cacheKey, cacheContent);
}public void removeCache(String cacheKey) {
cache.remove(cacheKey);
}public void reset() {
cache.clear();
}
}在使用中你可以把CacheProvider放到Global或者Visit對象中。注意要使用同一個CacheProvider。
我在google code host上面建了一個probject地址是http://code.google.com/p/tfancomponents/ 有興趣的同學可以看看, 這是一個maven項目。