以前写过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页面缓存简单的内容基本写完了,有不合理的地方请你们指正。