SpringMVC通过Redis实现缓存主页

http://blog.csdn.net/neosmith/article/details/46496353

首先,缓存主页的目的并不是提高性能,而是减少数据库访问压力,有效推迟数据库I/O瓶颈的到来。实现主页缓存的方法有很多,但是鉴于项目中使用了Redis对数据库读写做了缓存,因此把顺便也就把主页也缓存了吧。

实现思路

编写一个过滤器,在过滤器中拦截对主页的访问请求。此时向Redis服务器查询主页html的缓存,如果有则直接返回给客户端,如果没有,则在过滤器中截获JSP的渲染结果,放到Redis缓存中,以供下次使用。我们设定缓存过期时间为10分钟。

实现

实现需要注意的地方有两点:

如何在Servlet过虑器中使用Spring容器 如何截获JSP渲染结果
对于问题一,可以见我的另一篇博客:在Servlet Filter中使用Spring容器
对于问题二,我们可以继承HttpServletResponseWrapper类来巧妙实现:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class ResponseWrapper extends HttpServletResponseWrapper {
private PrintWriter cachedWriter;
private CharArrayWriter bufferedWriter;

public ResponseWrapper(HttpServletResponse response) {
    super(response);
    // 这个是我们保存返回结果的地方
    bufferedWriter = new CharArrayWriter();
    // 这个是包装PrintWriter的,让所有结果通过这个PrintWriter写入到bufferedWriter中
    cachedWriter = new PrintWriter(bufferedWriter);
}

@Override
public PrintWriter getWriter() {
    return cachedWriter;
}

/**
 * 获取原始的HTML页面内容。
 *
 * @return
 */
public String getResult() {
    return bufferedWriter.toString();
}

}
然后在过滤器中使用该类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class CacheFilter implements Filter, ApplicationContextAware {
private static final Logger log = LoggerFactory.getLogger(CacheFilter.class);

private static ApplicationContext ctx;

@Override
public void init(FilterConfig config) throws ServletException {
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    HttpServletResponse resp = (HttpServletResponse) servletResponse;
    HttpServletRequest req = (HttpServletRequest) servletRequest;

    // 如果不是访问主页,放行
    if (false == req.getRequestURI().equals("/")) {
        filterChain.doFilter(servletRequest, resp);
        return;
    }


    // 访问的是主页
    // 从缓存中得到主页html
    String html = getHtmlFromCache();
    if (null == html) {
        // 缓存中没有
        // 截取生成的html并放入缓存
        log.info("缓存不存在,生成缓存");
        ResponseWrapper wrapper = new ResponseWrapper(resp);
        // ***** 以上代码在请求被处理之前执行 *****

        filterChain.doFilter(servletRequest, wrapper);

        // ***** 以下代码在请求被处理后前执行 *****

        // 放入缓存
        html = wrapper.getResult();
        putIntoCache(html);

    }

    // 返回响应
    resp.setContentType("text/html; charset=utf-8");
    resp.getWriter().print(html);
}

@Override
public void destroy() {

}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.ctx = applicationContext;
}

private String getHtmlFromCache() {
    StringRedisTemplate redis = (StringRedisTemplate)ctx.getBean("redisTemplate");
    return redis.opsForValue().get("home");
}

private void putIntoCache(String html) {
    StringRedisTemplate redis = (StringRedisTemplate)ctx.getBean("redisTemplate");
    redis.opsForValue().set("home", html, TimeUnit.MINUTES.toSeconds(10)); // 10分钟
}

}
按照这个逻辑,当客户的GET请求为/时,CacheFilter会首先向Redis发起请求获取主页的html代码,如果成功,则直接返回给客户端,失败,则通过刚刚写好的ResponseWrapper截获主页JSP的渲染结果,放入Redis,并设置过期时间为10分钟。这样下次请求时就可以直接从缓存中读取,而不需要经过 Controller -> Service -> Dao -> Database这么费事的流程了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值