Oscache CacheFilter定时刷新和手动刷新缓存URL的实现

在写完上一篇关于Oscache CacheFilter手动刷新的文章( http://01404421.iteye.com/blog/510649)后,又感觉有些不太完美,虽然实现了可以控制的刷新但是又不能定时刷新,随后又看了一下源码,主要是com.opensymphony.oscache.web.filter.CacheFilter和com.opensymphony.oscache.web.filter.ExpiresRefreshPolicy,经过一个多小时终于实现了可以定时刷新和手动刷新的功能。废话不多说了,先贴代码:
web.xml
<filter>
  <filter-name>CacheFilter</filter-name>
	<filter-class>
		com.cache.MyFilterCache
	</filter-class>
	<init-param>
		<param-name>time</param-name>
		<param-value>8</param-value>
	</init-param>
  </filter>
  <filter-mapping>
	<filter-name>CacheFilter</filter-name>
	<url-pattern>/index.jsp</url-pattern>
  </filter-mapping>

定时8s自动刷新缓存。
com.cache.MyFilterCache
public class MyFilterCache extends CacheFilter{
	 private final Log log = LogFactory.getLog(this.getClass());
	@Override
	public void init(FilterConfig filterConfig) {
		// TODO Auto-generated method stub
		super.init(filterConfig);
		this.setExpiresRefreshPolicy(new MyEntryRefreshPolicy(this.getTime()));//初始化刷新策略
	}

	@Override
	public String createCacheKey(HttpServletRequest httpRequest, ServletCacheAdministrator scAdmin, Cache cache) {
	return httpRequest.getServletPath();//使用访问路径来作为缓存的key,也可以不设置
    }
}

createCacheKey这个方法大家可以不用重写也行,不影响。
要注意init方法中两句代码的次序,必须先调用super.init,因为在super中是用了一个Oscache自带的com.opensymphony.oscache.web.filter.ExpiresRefreshPolicy来作为刷新策略,所以我们的要放在后面来set进去覆盖默认的。默认的刷新只是根据时间来做判断。
一下是我们自己的刷新策略:
com.cache.MyEntryRefreshPolicy
public class MyEntryRefreshPolicy extends ExpiresRefreshPolicy{

	public MyEntryRefreshPolicy(int refreshPeriod) {
		// TODO Auto-generated constructor stub
		super(refreshPeriod);
	}

	@Override
	public boolean needsRefresh(CacheEntry entry) {
		// TODO Auto-generated method stub
		if(CacheUtil.isFLUSH()){
			CacheUtil.setFLUSH(false);
			return true;
		}
         return super.needsRefresh(entry);
	}
}

注意needsRefresh方法,最重要的就在这里(其实也很简单,呵呵),判断是否需要刷新,如果需要则返回true去刷新,如果不需要则再去判断时间,当然这里并不是很科学,毕竟手动刷新的几率较小,而每次都要去判断,最好应该放在按照时间判断的后面。以下是一个用来记录是否需要刷新的类:
public class CacheUtil {
	private static boolean FLUSH=false;//是否需要刷新缓存
	public static boolean isFLUSH() {
		return FLUSH;
	}
	public static void setFLUSH(boolean flush) {
		FLUSH = flush;
	}	
}

手动刷新时,只需要给这个CacheUtil.setFLUSH(true)就行了。
到这里就行了,不过在我学习Oscache源码的过程当中发现有个小问题很有趣,下面是
com.opensymphony.oscache.web.filter.ExpiresRefreshPolicy的源码:
public class ExpiresRefreshPolicy implements EntryRefreshPolicy {
    private long refreshPeriod;
    public ExpiresRefreshPolicy(int refreshPeriod) {
        this.refreshPeriod = refreshPeriod * 1000L;
    }   
    public boolean needsRefresh(CacheEntry entry) {      
        long currentTimeMillis = System.currentTimeMillis();      
        if ((refreshPeriod >= 0) && (currentTimeMillis >= (entry.getLastUpdate() + refreshPeriod))) {
            return true;
        } else if (entry.getContent() instanceof ResponseContent) {
            ResponseContent responseContent = (ResponseContent) entry.getContent();
            return currentTimeMillis >= responseContent.getExpires();
        } else {
            return false;
        }
        
    }
    public long getRefreshPeriod() {
        return refreshPeriod / 1000;
    }
    public void setRefreshPeriod(long refreshPeriod) {
        this.refreshPeriod = refreshPeriod * 1000L;
    }    
}

代码很简单吧,我去掉了所有的注释,我们都知道web.xml中设置的time参数单位是秒,但是实际上这里处理的时候是按照毫秒来处理的,从构造方法和set方法里将时间间隔乘1000,扩大为秒,其实最终用途只是用来比较时间戳的大小,个人感觉如果在并发量很大的情况下使用Oscache,这个乘1000的操作可能也会带来很大的性能损耗,其实完全可以在web.xml中按照毫秒来写,这里拿到后直接处理。
扩展一下:
以上例子只是用于一个URL,如果有多个url需要缓存同样可以设置单独刷新。不CacheUtil里可能就是一个MAP了。不过好像根据cache的key也可以刷新指定的cache,key的生产也是可以自己控制的,所以这个方案应该同样可以实现。不过刚开始我在测试group和key的刷新时没有成功,呵呵,以后再看看吧。
欢迎与各位交流。

你可能感兴趣的:(Web,xml,jsp,cache,Blog)