以前寫過spring cache和ehcache的基本介紹和註解實現緩存管理,今天記錄下web項目的頁面緩存技術。javascript
頁面緩存是否有必要?。html
這樣說吧,幾乎全部的網站的首頁都是訪問率最高的,而首頁上的數據來源又是很是普遍的,大多數來自不一樣的對象,並且有可能來自不一樣的db ,因此給首頁作緩存是很必要的。那麼主頁的緩存策略應該怎樣設計呢?我認爲應該是某個固定時間以內不變的,好比說2分鐘更新一次。那麼這個緩存應該作在什麼地方呢?讓咱們來看一下,當前咱們的的應用的結構通常是是page-filter-action-service-dao-db ,這個過程當中的- 的地方都是能夠作緩存的地方,根據頁面緩存的特徵,應該把頁面緩存作到儘可能靠近客戶的地方,就是在page 和filter 之間,這樣的優勢就是第一個用戶請求以後,頁面被緩存,第二個用戶再來請求的時候,走到filter 這個請求就結束了,無需再走後面的action-service-dao-db 。帶來的好處是服務器壓力的減低和客戶段頁面響應速度的加快。瞭解了這些以後咱們開始介紹重點。java
ehcache頁面緩存的特色:緩存中的元素是被壓縮過的,若是客戶瀏覽器支持壓縮的話,filter 會直接返回壓縮過的流,這樣節省了帶寬,把解壓的工做交給了客戶瀏覽器,若是客戶的瀏覽器不支持gzip ,那麼filter 會把緩存的元素拿出來解壓後再返回給客戶瀏覽器(大多數爬蟲是不支持gzip 的,因此filter 也會解壓後再返回流),這樣作的優勢是節省帶寬,缺點就是增長了客戶瀏覽器的負擔jquery
1 .SimplePageCachingFilterweb
它ehcache-web模塊下頁面緩存Filter的一個簡單實現,適用於能夠壓縮的Http響應(response),如HTML、XML、JSON等。它會使用經過CacheManager的靜態方法create建立的單例CacheManager,這樣若是以前已經存在CacheManager的實例了的話,這裏就會直接拿來用,而不會再建立了。因此這裏通常默認狀況下會取類根路徑下的ehcache.xml文件來建立CacheManager,但若是咱們的項目中整合了Ehcache和Spring,且在Spring配置文件中指定的Ehcache的配置文件不是默認位置的話,Spring將使用指定的配置文件優先初始化CacheManager,這樣SimplePageCachingFilter中要使用CacheManager時就不會再初始化了,而是直接使用Spring初始化的。頁面緩存使用的key是經過SimplePageCachingFilter的calculateKey()方法獲取的。其內部邏輯是獲取請求時的URI及後面的查詢字符串做爲key進行返回,如「/user/index.jsp?name=abc」,這使得它的應用範圍很是廣。它不依賴於主機名和端口號,這將使得它一樣適用於有多個域或多個端口請求一樣內容的狀況。若是有須要,咱們能夠對calculateKey方法進行重寫,從而實現咱們本身的計算key的邏輯。這個是頗有必要的,由於在項目中不少頁面都使用AJAX,爲保證JS請求的數據不被瀏覽器緩存,每次請求可能都會是不一樣的數參數。若是使用 SimplePageCachingFilter,那麼每次生成的key都不同,緩存就沒有意義了。這種狀況下,咱們就會覆寫 calculateKey()方法。spring
2 .SimpleCachingHeadersPageCachingFilter 提供HTTP緩存頭信息,這個不介紹了用的不多。瀏覽器
3 .SimplePageFragmentCachingFilter 緩存
SimplePageCachingFilter適用於緩存整個頁面的狀況,若是隻須要緩存某一個片斷,如使用jsp:include包含的部分,這個時候就須要用SimplePageFragmentCachingFilter。服務器
第一部分是頁面總體緩存app
第一步:首先配置ehcache.xml指定咱們的SimplePageCachingFilter緩存 ,這裏指定頁面緩存的生命週期是60秒,還有timeToIdleSeconds的時間愛你是120秒,這裏要注意下不要設置太長時間
<!-- 頁面所有緩存 --> <cache name="SimplePageCachingFilter" maxElementsInMemory="10" maxElementsOnDisk="10" eternal="false" overflowToDisk="false" timeToIdleSeconds="120" timeToLiveSeconds="60" memoryStoreEvictionPolicy="LFU">
</cache>
第二步 : 在web.xml中添加頁面緩存過濾器PageCachingFilter。
注意: 若是咱們在ehcache.xml中命名的頁面緩存名字爲SimplePageCachingFilter時,咱們再web.xml中的頁面緩存過濾器的cacheName是能夠不用定義的,由於它是默認的;若是不是SimplePageCachingFilter,這是我就必須指定cacheName了。
還有一點url-pattern的指定應該是/pageCacheController/testPageCache.do,而不是/testPageCache.do這個。
<!--ehcache 頁面緩存過濾器 --> <filter> <filter-name>PageCachingFilter</filter-name> <filter-class>net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter</filter-class> <init-param> <param-name>cacheName</param-name> <param-value>SimplePageCachingFilter</param-value> </init-param> </filter> <filter-mapping> <filter-name>PageCachingFilter</filter-name> <url-pattern>/pageCacheController/testPageCache.do</url-pattern> </filter-mapping>
第三步 : 編寫controller測試類
@Controller @RequestMapping("pageCacheController") public class PageCacheController { private final static Logger log = Logger.getLogger(PageCacheController.class); @RequestMapping("testPageCache") public ModelAndView testPageCache(){ ModelMap model = new ModelMap(); Date date = new Date(); model.addAttribute("date", date.toLocaleString() ); log.info("我來訪問controller了"); return new ModelAndView("testPageCache",model); } }
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>測試</title> <script type="text/javascript" src="<%=request.getContextPath()%>/js/jquery-1.11.1.min.js"></script> <script type="text/javascript"> </script> </head> <body> <h1>這是一個頁面緩存的練習</h1> <font style="color:green;font-weight:bold;font-size: 18px">${date}</font><br><br> </body> </html>
上面這個是testPageCache.jsp頁面
第四步 : 訪問/pageCacheController/testPageCache.do觀察頁面時間並查看控制檯輸出,在該緩存的生命週期內,即60秒之間刷新頁面,頁面上的時間是不會變化的,當過了緩存的生命週期在訪問,時間立馬改變。下面看看圖。
在60秒內刷新頁面觀看控制檯。發現「我來訪問controller了」沒有打印出來,也就是說在緩存生命週期內咱們第二次訪問時,只通過了page-filter-action-service-dao-db 中的page-filter其他的部分都沒有訪問。若是你親自作過的話你會對控制檯打印的信息會產生興趣的,我這裏給指出一個重要的Cache-control-> max-age=0,這個大家能夠研究研究,我就不說了。
到這裏頁面總體緩存的簡單例子就完成了,固然實際項目中確定比這複雜,可是道理是同樣的。只要你明白其中的原理,那麼一切OK!
第二部分是頁面局部緩存
道理跟上面的同樣我就簡單說了
配置ehcache.xml
<!-- 頁面局部緩存 --> <cache name="SimplePageFragmentCachingFilter" maxElementsInMemory="10" maxElementsOnDisk="10" eternal="false" overflowToDisk="false" timeToIdleSeconds="120" timeToLiveSeconds="60" memoryStoreEvictionPolicy="LFU"> </cache>
配置web.xml,這裏須要注意幾點,咱們include的jsp頁面在filter中要指定<dispatcher>INCLUDE</dispatcher>,若是沒有指定任何< dispatcher >元素,默認值是REQUEST就不會攔截了。我這裏有新增長了一個頁面做爲include的頁面
<!--ehcache 頁面局部緩存 --> <filter> <filter-name>PageFragmentCachingFilter</filter-name> <filter-class>net.sf.ehcache.constructs.web.filter.SimplePageFragmentCachingFilter</filter-class> <init-param> <param-name>cacheName</param-name> <param-value>SimplePageFragmentCachingFilter</param-value> </init-param> </filter> <!-- This is a filter chain. They are executed in the order below.Do not change the order. --> <filter-mapping> <filter-name>PageFragmentCachingFilter</filter-name> <url-pattern>/page/testPageFragmentCache.jsp</url-pattern> <dispatcher>INCLUDE</dispatcher> </filter-mapping>
testPageFragmentCache.jsp頁面,爲了方便我仍是調用了上邊的controller方法來觀察時間。若是你是按照個人作法一步一步作的話,要測試局部緩存時,須要把頁面總體緩存的filter註釋掉,實際中不須要,只是我爲了偷懶用了相同訪問地址
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>測試</title> </head> <body> <h1>這是include的jsp頁面</h1> <font style="color:green;font-weight:bold;font-size: 18px">${date}</font><br><br> </body> </html>
下面來看效果圖
刷新頁面,沒有變化說明咱們include的頁面被緩存了
來看看控制檯變化
OK頁面緩存簡單的內容基本寫完了,有不合理的地方請你們指正。