ehcache web 页面缓存实例

Ehcahe-web概念

Ehcahe在ehcache-web中提供了一套通用的web缓存过滤器,可以高效的进行压缩、存储以及网络传输。缓存的页面和片段也可以很好的存储到磁盘上,因为使用了简单的对象描述和大部分的二进制格式。对于一般的硬件可以提供每秒5000+的访问量。

ehcache-web组件
       SimplePageCachingFilter 是一个简单的缓存过滤器,适合缓存可压缩的HTTP响应,比如HTML、XML、js、css或者JSON。它使用了一个单例的CacheManager。
Keys
缓存的key默认使用的是URI加请求字符串,例如: /admin/SomePage.jsp?id=1234&name=Beagle. 如果没有请求参数可以为 /admin/SomePage.jsp?null
你也可以继承SimplePageCachingFilter覆盖calculateKey(javax.servlet.http.HttpServletRequest)方法,生成自己的key
压缩
通过压缩可以得到更快的网络传输和页面加载速度。响应是否应该被缓存根据:
1.用户代理具有接收GZIP编码的功能。这个特性是HTTP1.1的一部分。如果一个浏览器接收GZIP编码,它将会在HTTP头中标示出来:所有一般的浏览器除了IE5.2在Macintosh上,都能够接收gzip编码。大多数搜索引擎机器人不接受gzip编码。
2.request必须包含HTTP请求头:Accept-Encoding: gzip

响应将会自动的压缩保存在cache中。对于不支持gzip编码的请求,页面会从cache中获取并解压然后返回给用户代理。解压过程是很高效的。

像本博客网站一样,页面一般都是固定的,所以使用了ehcache-web作为页面缓存。代码:
1.首先在ehcache.xml配置用于页面的缓存       

<cache name="pageCache" 
 maxElementsInMemory="1000" 
 eternal="true"
 timeToIdleSeconds="120"
 timeToLiveSeconds="120"
 overflowToDisk="false" 
 memoryStoreEvictionPolicy="LFU"/>

2.在web.xml配置filter过滤需要缓存的url

<filter>
    <filter-name>PageEhCacheFilter</filter-name>
    <filter-class>com.qyd.blog.web.filter.PageEhCacheFilter</filter-class>
        <init-param>
            <param-name>cacheName</param-name>
            <param-value>pageCache</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>PageEhCacheFilter</filter-name>
        <url-pattern>/*</url-pattern><!--这里拦截所有页面,在filter中通过正则表达式确定是否缓存url-->
    </filter-mapping>
</filter>

3. 因为ie6和ie7是支持gzip编码的,但在请求头中确没有包含Accept-Encoding: gzip,所以编写自定义的PageEhCacheFilter类,实现SimplePageCachingFilter,覆盖它用于判断是否返回 gzip编码的方法boolean acceptsGzipEncoding(HttpServletRequest request)

package com.qwyd.blog.web.filter;
import java.util.Enumeration;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.ehcache.constructs.blocking.LockTimeoutException;
import net.sf.ehcache.constructs.web.AlreadyCommittedException;
import net.sf.ehcache.constructs.web.AlreadyGzippedException;
import net.sf.ehcache.constructs.web.filter.FilterNonReentrantException;
import net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter;
/**
 * 页面缓存过滤器
 * @version 1.0
 */
public class PageEhCacheFilter extends SimplePageCachingFilter {
    private static final Logger LOG = LoggerFactory.getLogger(PageEhCacheFilter.class);
    
    @Override
    protected void doFilter(final HttpServletRequest request, final HttpServletResponse response,
            final FilterChain chain) throws AlreadyGzippedException, AlreadyCommittedException,
            FilterNonReentrantException, LockTimeoutException, Exception {
        if (isCacheAble(request.getRequestURI())) {
            LOG.debug("缓存url:" + request.getRequestURI());
            super.doFilter(request, response, chain);
        } else {
            chain.doFilter(request, response);
        }
    }
    private boolean isCacheAble(String requestURI) {
           //通过正则表达式判断是否缓存该页面
        String[] cacheUrl = new String[] { 
                "^/$", "^/\\d+/$",
                "^/[A-Za-z_]+/$","^/[A-Za-z_]+/\\d+/$",//包含java和seo路径
                "^/about/$"};
        for (String string : cacheUrl) {
            if (requestURI.matches(string)) {
                return true;
            }
        }
        return false;
    }
    /**
     * Checks if request contains the header value.
     */
    private boolean headerContains(final HttpServletRequest request, final String header, final String value) {
        logRequestHeaders(request);
        final Enumeration accepted = request.getHeaders(header);
        while (accepted.hasMoreElements()) {
            final String headerValue = (String) accepted.nextElement();
            if (headerValue.indexOf(value) != -1) {
                return true;
            }
        }
        return false;
    }
    /**
     * @see net.sf.ehcache.constructs.web.filter.Filter#acceptsGzipEncoding(javax.servlet.http.HttpServletRequest)
     * 兼容ie6/7 gzip压缩
     * @author hoojo
     * @createDate 2012-7-4 上午11:07:11
     */
    @Override
    protected boolean acceptsGzipEncoding(HttpServletRequest request) {
        boolean ie6 = headerContains(request, "User-Agent", "MSIE 6.0");
        boolean ie7 = headerContains(request, "User-Agent", "MSIE 7.0");
        return acceptsEncoding(request, "gzip") || ie6 || ie7;
    }
}

        非常简单,这样就完成了页面缓存,当第一次访问http://www.javaseo.cn/时过滤器会压缩缓存jsp解析后的html文件,以后访问直接返回缓存中压缩后的html文件,不会执行你的controller或者action。
你也可以在web.xml配置过滤js、css文件,同样可以压缩。如jquery-min.js大概90k左右,通用ehcache-web压缩后只有50k左右,这样极大的提高了页面加载速度。
要压缩缓存js、css,在web.xml 过滤器filter-mapping中加入:

<filter-mapping>
    ...
    <filter-name>PageEhCacheFilter</filter-name>
    <url-pattern>*.js</url-pattern>
    <filter-name>PageEhCacheFilter</filter-name>
    <url-pattern>*.css</url-pattern>
</filter-mapping>


ehcache-web还包含SimplePageFragmentCachingFilter用于缓存某一个片段,如使用jsp:include包含的部分。
SimpleCachingHeadersPageCachingFilter 缓存的页面信息同时设置“Last-Modified、Expires、Cache-Control、ETag”这四个头信息的。这样当缓存中存在对应的 页面时,所有的请求获取到的页面的头信息都会是一样的,与SimplePageCachingFilter不同的是在Expires到期前浏览器不会访问服务器,也就没法获取到最新数据。
(本文基于Ehcache Web Cache User Guide Version 2.10.1和本博客源码编写)

...条评论

加载更多评论