设为首页 加入收藏

TOP

SpringMVC通过Redis实现缓存主页
2015-07-16 12:55:16 来源: 作者: 【 】 浏览:3
Tags:SpringMVC 通过 Redis 实现 主页

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


实现思路


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


实现


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


如何在Servlet过虑器中使用Spring容器


如何截获JSP渲染结果


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();
? ? }
}


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


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这么费事的流程了。


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇在Servlet Filter中使用Spring容器 下一篇awk转义序列与算术操作符

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: