页面整页缓存注解方法

1、JFinalConfig configInterceptor方法最后加入:

me.add(new ViewCacheInterceptor());

2、在需要缓存页面的Controller方法中进行注解:

/**
 * @param view 与render(view)中的view相同
 * @param live 缓存存活时间(单位:秒),对应EhCache的TimeToLive
 * @param idle 缓存空闲时间(单位:秒),对应EhCache的TimeToIdle
 */
@ViewCache(view = "index.html", live = 60, idle = 0)
public void index() {
    int pageNumber = getParaToInt("p", 1);
    int pageSize = getParaToInt("s", 10);
    Page<Role> page = srv.getPage(pageNumber, pageSize);
    setAttr("page", page);
    render("index.html");
}

3、清除缓存方法(不提供,自行处理)

   缓存命名规则如下:

   cacheName: controller.getClass().getName()

   cacheKey:  methodName + ":" + urlParas

   如清除以上第2步的index方法缓存,可根据cacheName遍历对“index”开头的cacheKey进行清除即可。

4、最后上代码

ViewCache.class代码:

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface ViewCache {
	String view();
	int live();
	int idle();
}

ViewCacheInterceptor.class代码:

public class ViewCacheInterceptor implements Interceptor {

    private static ConcurrentHashMap<String, ReentrantLock> lockMap = new ConcurrentHashMap<String, ReentrantLock>();
	
    @Override
    public void intercept(Invocation inv) {
	ViewCache viewCache = inv.getMethod().getAnnotation(ViewCache.class);
	if ( viewCache != null ) {
            Controller c = inv.getController();
            String cacheName = c.getClass().getName();
            String cacheKey = getCacheKey(c, inv.getMethodName());
            String cacheData = CacheKit.get(cacheName, cacheKey);
            if ( cacheData != null ) {
		c.renderHtml(cacheData);
	    } else {
		inv.invoke();
		buildCache(inv, c, cacheName, cacheKey, viewCache);
	    }
	    return;
	}
		
	inv.invoke();		
    }
	
    private ReentrantLock getLock(String key) {
	ReentrantLock lock = lockMap.get(key);
	if ( lock != null ) {
	    return lock;
	}
	lock = new ReentrantLock();
	ReentrantLock previousLock = lockMap.putIfAbsent(key, lock);
	return previousLock == null ? lock : previousLock;
    }
	
    private String getCacheKey(Controller c, String methodName) {
	StringBuilder sb = new StringBuilder(c.getClass().getName());
	String urlPara = c.getPara();
	if ( urlPara != null ) {
	    sb.append('/').append(urlPara);
	}
	String queryString = c.getRequest().getQueryString();
	if ( queryString != null ) {
	    sb.append('?').append(queryString);
	}
	return sb.length() > 0 ? methodName + ":" + sb.toString() : methodName;
    }
	
    private void buildCache(Invocation inv, Controller c, String cacheName, String cacheKey, ViewCache viewCache) {
	Lock lock = getLock(cacheName);
	lock.lock(); // prevent cache snowslide
	try {
	    Object cacheData = CacheKit.get(cacheName, cacheKey);
	    if ( cacheData == null ) {
	        Map<String, Object> map = new HashMap<String, Object>();
	        for (Enumeration<String> names = c.getRequest().getAttributeNames(); names.hasMoreElements();) {
		    String name = names.nextElement();
		    map.put(name, c.getRequest().getAttribute(name));
	        }
				
	        String view = viewCache.view();
	        if (view != null && view.length() > 0 && view.charAt(0) != '/') {
		    view = inv.getViewPath() + view;
	        }
				
	        putCache(cacheName, cacheKey, c.renderToString(view, map), viewCache.live(), viewCache.idle());
	    }
	} finally {
	    lock.unlock();
	}
    }
	
    private void putCache(String cacheName, Object key, Object value, int live, int idle) {
	Element element = new Element(key, value);
	element.setEternal(false);
	element.setTimeToLive(live);//单位:秒;对象存活时间,指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问
	element.setTimeToIdle(idle);//单位:秒;对象空闲时间,指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问
	getOrAddCache(cacheName).put(element);
    }
		
    private Cache getOrAddCache(String cacheName) {
	CacheManager cacheManager = CacheKit.getCacheManager();
	Cache cache = cacheManager.getCache(cacheName);
	if ( cache == null ) {
	    cacheManager.addCacheIfAbsent(cacheName);
	    cache = cacheManager.getCache(cacheName);
	}
	return cache;
    }

}


评论区

爪爪

2017-07-04 11:26

大神这个缓存,带参数、不带参数已经不同的参数缓存可以区别出来对吧对吧,我看见构造key不一样,我有个类似的问题 一直没解决 看到你这个有了想法,你这个锁的使用能大体描述以下原因吗?是因为这个拦截器是全局共享的吗

飞.飞

2017-07-04 19:32

@爪爪 会对不同参数生成不同缓存。加锁是针对并发处理,Ehchace也有加锁方法acquireWriteLockOnKey,ReentrantLock是抄波总的代码段,目前还没时间研究有两者有什么区别..

JFinal

2017-07-04 20:58

这个方案用起来非常方便,连 cache 的配置都能在注解中搞定,赞一个

爪爪

2017-07-04 21:07

热门分享

扫码入社