這裡說的緩存只是為了提供一些動態的界面沒辦法作靜態化的界面來減少資料庫的訪問壓力,如果能夠做靜態化的話的還是採用nginx來做界面的靜態化,這樣可以承受高併發的訪問能力。 好了,廢話少說直接看實現代碼吧下載地址, 實現機制主要是通過過濾器攔截方案,有兩個地方要註意的 1,Servlet過慮器中使用S
這裡說的緩存只是為了提供一些動態的界面沒辦法作靜態化的界面來減少資料庫的訪問壓力,如果能夠做靜態化的話的還是採用nginx來做界面的靜態化,這樣可以承受高併發的訪問能力。 好了,廢話少說直接看實現代碼吧下載地址, 實現機制主要是通過過濾器攔截方案,有兩個地方要註意的 1,Servlet過慮器中使用Spring容器 2,截獲JSP渲染結果保存redis中 首先看第一個Servlet過慮器中使用Spring容器 定義一個filter, 實現ApplicationContextAware介面 Java代碼 收藏代碼 public class CacheFilter implements Filter, ApplicationContextAware { private static ApplicationContext ctx; // 必須聲明為static @Override public void init(FilterConfig config) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { CacheFilter.ctx = applicationContext; // 保存spring容器到static變數中 } 配置spring的bean Java代碼 收藏代碼 <bean class="com.zhang.example.servlet.CacheFilter" id="cacheFilter"></bean> web.xml中的聲明 Java代碼 收藏代碼 <filter> <filter-name>Cache Filter</filter-name> <filter-class>com.zhang.example.servlet.CacheFilter</filter-class> </filter> <filter-mapping> <filter-name>Cache Filter</filter-name> <servlet-name>/</servlet-name> </filter-mapping> 這時,我們就可以在doFilter()方法中直接通過ApplicationContext檢索需要的bean了 Java代碼 收藏代碼 StringRedisTemplate redis = (StringRedisTemplate)ctx.getBean("redisTemplate"); 二,截獲JSP渲染結果 Java代碼 收藏代碼 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(); } } Java代碼 收藏代碼 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分鐘。這樣下次請求時就可以直接從緩存中讀取