关于CacheInterceptor之beetl的使用

/**

 * Copyright (c) 2011-2016, James Zhan 詹波 (jfinal@126.com).

 *

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *      http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */



import java.util.Enumeration;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import java.util.Map.Entry;

import java.util.Set;

import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

import javax.servlet.http.HttpServletRequest;

import com.jfinal.aop.Interceptor;

import com.jfinal.aop.Invocation;

import com.jfinal.core.Controller;

import com.jfinal.plugin.ehcache.CacheKit;

import com.jfinal.plugin.ehcache.CacheName;

import com.jfinal.render.Render;


/**

 * CacheInterceptorEx. 页面缓存,根据CacheInterceptor修改,因为它不支持beetl 而EvictInterceptor依然使用

 */

public class CacheInterceptorEx implements Interceptor {

private static final String renderKey = "_renderKey";

private static ConcurrentHashMap<String, ReentrantLock> lockMap = new ConcurrentHashMap<String, ReentrantLock>();

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;

}

final public void intercept(Invocation inv) {

Controller controller = inv.getController();

String cacheName = buildCacheName(inv, controller);

String cacheKey = buildCacheKey(inv, controller);

Map<String, Object> cacheData = CacheKit.get(cacheName, cacheKey);

if (cacheData == null) {

Lock lock = getLock(cacheName);

lock.lock(); // prevent cache snowslide

try {

cacheData = CacheKit.get(cacheName, cacheKey);

if (cacheData == null) {

inv.invoke();

cacheAction(cacheName, cacheKey, controller);

return ;

}

}

finally {

lock.unlock();

}

}

useCacheDataAndRender(cacheData, controller);

}

// TODO 考虑与 EvictInterceptor 一样强制使用  @CacheName

private String buildCacheName(Invocation inv, Controller controller) {

CacheName cacheName = inv.getMethod().getAnnotation(CacheName.class);

if (cacheName != null)

return cacheName.value();

cacheName = controller.getClass().getAnnotation(CacheName.class);

return (cacheName != null) ? cacheName.value() : inv.getActionKey();

}

private String buildCacheKey(Invocation inv, Controller controller) {

StringBuilder sb = new StringBuilder(inv.getActionKey());

String urlPara = controller.getPara();

if (urlPara != null)

sb.append("/").append(urlPara);

String queryString = controller.getRequest().getQueryString();

if (queryString != null)

sb.append("?").append(queryString);

return sb.toString();

}

private void cacheAction(String cacheName, String cacheKey, Controller controller) {

HttpServletRequest request = controller.getRequest();

Map<String, Object> cacheData = new HashMap<String, Object>();

for (Enumeration<String> names=request.getAttributeNames(); names.hasMoreElements();) {

String name = names.nextElement();

cacheData.put(name, request.getAttribute(name));

}

Render render = controller.getRender();

if (render != null) {

                       // cacheData.put(renderKey, new RenderInfo(render)); // cache RenderInfo

                        cacheData.put(renderKey, render.getView()); // cache RenderInfo

}

CacheKit.put(cacheName, cacheKey, cacheData);

}

private void useCacheDataAndRender(Map<String, Object> cacheData, Controller controller) {

HttpServletRequest request = controller.getRequest();

Set<Entry<String, Object>> set = cacheData.entrySet();

for (Iterator<Entry<String, Object>> it=set.iterator(); it.hasNext();) {

Entry<String, Object> entry = it.next();

request.setAttribute(entry.getKey(), entry.getValue());

}

request.removeAttribute(renderKey);

// RenderInfo renderInfo = (RenderInfo)cacheData.get(renderKey);

// if (renderInfo != null) {

// controller.render(renderInfo.createRender()); // set render from cacheData

// }

controller.render((String)cacheData.get(renderKey));

}

}

发现只保存view也可以

评论区

JFinal

2016-12-12 14:54

对于有些只有 view 这个属性的 render ,可以只保存 view,然后在从缓存取出来的时候恢复一下这个值即可,但对于 JsonRender 这类有多个属性的 render,就需要恢复出更多的属性值来才能重建 render 对象,所以对于框架来说,需要通过接口或抽象的方式来做成通用的

感谢分享

songhuaming2000

2016-12-12 15:11

谢谢指教

热门分享

扫码入社