文档章节

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

冷冷gg
 冷冷gg
发布于 2017/04/06 13:15
字数 622
阅读 134
收藏 0

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

© 著作权归作者所有

共有 人打赏支持
冷冷gg
粉丝 432
博文 113
码字总数 52275
作品 1
潍坊
UI设计师
私信 提问
加载中

评论(1)

故宫导览小程序
故宫导览小程序
这个操作666,收藏了
JFinal 2.0 发布,JAVA 极速 WEB+ORM 框架

JFinal 是本星球第一个提出极速开发理念,也是唯一个极速开发框架。自开源以来迅速获得广大开发者的喜爱,极速开发的优势逐步深入人心。由于极速开发威力巨大,所以有了以下在 OSChina 的惊人...

JFinal
2015/06/18
26.2K
405
JFinal框架学习-------EhCachePlugin

一.关于EhCachePlugin 在之前的文章中,我们已经介绍过了JFinal中Cache的一些简单使用,这篇文章将讲述EhCachePlugin的使用, EhCachePlugin是JFinal集成的缓存插件,通过使用EhCachePlugin...

Carol998
10/11
0
0
JFinal中关于CacheInterceptor的用法疑问

@JFinal ,最近需要用到缓存方面的功能,看了jfinal的文档,说里面有一个CacheInterceptor拦截器,可以将本action检索的数据缓存起来,下次不用再检索,直接使用缓存的数据去render一个html文...

会哭的鳄鱼
02/05
145
3
JFinal 2.1 发布,用 JFinal 开发,就这么定了!

JFinal 2.1 将带给大家超过60项增强与改进,此次升级核心目的,一是全面解救传统SSH开发者,强力推动这些早已累成狗的工程师转投 JFinal 怀抱,二是与老用户建立更深的情感,答谢你们长久以来...

JFinal
2015/12/29
25K
354
Jboot 1.0-rc.1 发布,基于 JFinal 的微服务框架

Jboot终于发布了第一个RC版本了。 在此之前,Jboot发布了5个alpha版本,9个beta版本。 Jboot RC版本的发布,也意味着Jboot设想的、企业开发中最最常用的功能已经全部支持完毕,这些功能包含了...

理工男海哥
2017/10/12
1K
10

没有更多内容

加载失败,请刷新页面

加载更多

mac 下 mysql 8.0.13 安装并记录遇到的问题 以便以后查看

安装 官网mysql 下载地址 安装过程 省去 安装好之后 下载navicat 错误1 链接 遇到 mysql 2003 - Can't connect to MySQL server 错误, 解决方案 重启mysql 服务 #错误2 ERROR 1045: Acces...

杭州-IT攻城狮
32分钟前
3
0

中国龙-扬科
35分钟前
1
0
[Spring4.x]基于spring4.x纯注解的Web工程搭建

在前文中已经说明了如何基于 Spring4.x+ 版本开发纯注解的非web项目,链接如下: https://my.oschina.net/morpheusWB/blog/2985600 本文则主要说明,如何在Web项目中,"基于spring纯注解方式...

morpheusWB
今天
13
0
基础编程题目集-7-13 日K蜡烛图

股票价格涨跌趋势,常用蜡烛图技术中的K线图来表示,分为按日的日K线、按周的周K线、按月的月K线等。以日K线为例,每天股票价格从开盘到收盘走完一天,对应一根蜡烛小图,要表示四个价格:开...

niithub
今天
5
0
Jenkins window 下的安装使用

1.下载:https://jenkins.io/download/ 双击安装完毕,将自动打开浏览器: http://localhost:8080 打开对应位置的文件,将初始密钥粘贴至输入框。 第一个是 安装默认的软件;第二个是 自定义...

狼王黄师傅
今天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部