【jfinal修仙系列】扩展CacheInterceptor支持Redis缓存
博客专区 > 冷冷gg 的博客 > 博客详情
【jfinal修仙系列】扩展CacheInterceptor支持Redis缓存
冷冷gg 发表于9个月前
【jfinal修仙系列】扩展CacheInterceptor支持Redis缓存
  • 发表于 9个月前
  • 阅读 97
  • 收藏 2
  • 点赞 0
  • 评论 0

标题:腾讯云 新注册用户域名抢购1元起>>>   

摘要: 【jfinal修仙系列】扩展CacheInterceptor支持Redis缓存

jfinal内置CacheInterceptor

  1. 依赖于EhCachePlugin,是基于ehcache的。
  2. CacheInterceptor 可以将 action 所需数据全部缓存起来,下次请求到来时如果 cache 存在则直接使用数据并 render,而不会去调用 action。此用法可使 action 完全不受 cache相关代码所 污染,即插即用,以下是示例代码:
@Before(CacheInterceptor.class)
public void list() {
    List<Blog> blogList = Blog.dao.find("select * from blog");
    User user = User.dao.findById(getParaToInt());
    setAttr("blogList", blogList);
    setAttr("user", user);
    render("blog.html");
}
  1. EvictInterceptor 可以根据 CacheName 注解自动清除缓存。以下是示例代码: 上例中的用法将清除 cacheName 为 blogList 的缓存数据,与其配合的 CacheInterceptor 会 自动更新 cacheName 为 blogList 的缓存数据。

扩展CacheInterceptor支持Redis缓存

public class RedisCacheInterceptor implements Interceptor {
    private static final String renderKey = "_renderKey";
    private static final String prefixKey = "intercept_";
    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;
    }

    public void intercept(Invocation inv) {
        Controller controller = inv.getController();
        String cacheName = buildCacheName(inv, controller);
        String cacheKey = buildCacheKey(inv, controller);
        Map<String, Object> cacheData = Redis.use().hget(cacheName, cacheKey);
        if (cacheData == null) {
            Lock lock = getLock(cacheName);
            lock.lock();
            try {
                cacheData = Redis.use().hget(cacheName, cacheKey);
                if (cacheData == null) {
                    inv.invoke();
                    cacheAction(cacheName, cacheKey, controller);
                    return;
                }
            } finally {
                lock.unlock();
            }
        }

        useCacheDataAndRender(cacheData, controller);
    }

    private String buildCacheName(Invocation inv, Controller controller) {
        CacheName cacheName = inv.getMethod().getAnnotation(CacheName.class);
        if (cacheName != null)
            return prefixKey + cacheName.value();
        cacheName = controller.getClass().getAnnotation(CacheName.class);
        return (cacheName != null) ? prefixKey + cacheName.value() : prefixKey + 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, createRenderInfo(render));        // cache RenderInfo
        }
        Redis.use().hset(cacheName, cacheKey, cacheData);
    }

    private RenderInfo createRenderInfo(Render render) {
        return new RenderInfo(render);
    }

    private void useCacheDataAndRender(Map<String, Object> cacheData, Controller controller) {
        HttpServletRequest request = controller.getRequest();
        Set<Map.Entry<String, Object>> set = cacheData.entrySet();

        for (Map.Entry<String, Object> entry : set) {
            request.setAttribute(entry.getKey(), entry.getValue());
        }
        request.removeAttribute(renderKey);

        RenderInfo renderInfo = (RenderInfo) cacheData.get(renderKey);
        if (renderInfo != null) {
            controller.render(renderInfo.createRender());
        }
    }


}

扩展RedisEvictInterceptor,清除缓存

/**
 * Created by jie on 2017/4/5.
 * 根据CacheName清除
 * 必须配合 @CacheName 使用
 */
public class RedisEvictInterceptor implements Interceptor {
    private static final String prefixKey = "intercept_";

    final public void intercept(Invocation inv) {
        inv.invoke();
        Redis.use().del(buildCacheName(inv));
    }

    private String buildCacheName(Invocation inv) {
        CacheName cacheName = inv.getMethod().getAnnotation(CacheName.class);
        if (cacheName != null)
            return prefixKey + cacheName.value();

        cacheName = inv.getController().getClass().getAnnotation(CacheName.class);
        if (cacheName == null)
            throw new RuntimeException("EvictInterceptor need CacheName annotation in controller.");
        return prefixKey + cacheName.value();
    }
}

使用

@Before(RedisCacheInterceptor.class)
public void test(){
    render("test/test.html");
}

@Before(RedisCacheInterceptor.class)
@CacheName("test1")
public void test1(){
    render("test/test.html");
}
Redis缓存结果

image

标签: JFinal Java Redis
共有 人打赏支持
粉丝 104
博文 103
码字总数 44380
作品 1
×
冷冷gg
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: