首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【jfinal修仙系列】扩展CacheInterceptor支持Redis缓存

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

作者头像
冷冷
发布2018-02-08 12:23:47
6930
发布2018-02-08 12:23:47
举报
文章被收录于专栏:冷冷冷冷

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
image
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • jfinal内置CacheInterceptor
  • 扩展CacheInterceptor支持Redis缓存
  • 扩展RedisEvictInterceptor,清除缓存
  • 使用
    • Redis缓存结果
    相关产品与服务
    云数据库 Redis
    腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档