Spring MVC3整合缓存Ehcache实现

最近项目中需要用到缓存,在网上搜了大堆资料,发现Ehcache很好用,用法也比较简单。用简单的配置就可以使用了,而且Ehcache可以对页面、对象、数据进行缓存。Spring对Ehcache的支持也非常好。EHCache支持内存和磁盘的缓存,支持多种淘汰算法(LRU、LFU和FIFO)。

一、本教程环境

Spring 3.2.5 支持 http://pan.baidu.com/s/1hq3To8k

Ehcache 对象、数据缓存:http://ehcache.org/downloads/destination?name=ehcache-core-2.5.2-distribution.tar.gz&bucket=tcdistributions&file=ehcache-core-2.5.2-distribution.tar.gz

Ehcache Web页面缓存:http://ehcache.org/downloads/destination?name=ehcache-web-2.0.4-distribution.tar.gz&bucket=tcdistributions&file=ehcache-web-2.0.4-distribution.tar.gz

把jar加入到lib目录下

ehcache-core中可以找到 ehcache.xmlehcache.xsd着两个配置文件放到项目src下的配置文件目录

二、页面缓存

页面缓存主要用Filter过滤器对请求的url进行过滤,如果该url在缓存中出现。那么页面数据就从缓存对象中获取,并以gzip压缩后返回。其速度是没有压缩缓存时速度的3-5倍,效率相当之高!


在ehcache.xml中加入如下配置:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:noNamespaceSchemaLocation="ehcache.xsd">
	<!--
	name:Cache的唯一标识
	maxElementsInMemory:内存中最大缓存对象数
	maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大
	eternal:Element是否永久有效,一但设置了,timeout将不起作用
	overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中
	timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大
	timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间无穷大 意思是从cache中的某个元素从创建到消亡的时间,从创建开始计时,当超过这个时间,这个元素将被从cache中清除
	diskPersistent:是否缓存虚拟机重启期数据
	diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒
	diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
	memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用) 
	-->
<pre name="code" class="html">       <diskStore path="java.io.tmpdir"/>
 <defaultCache maxElementsInMemory="20000" overflowToDisk="true" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="3600" />
<cache name="SimplePageCachingFilter" maxElementsInMemory="20000" maxElementsOnDisk="20000" eternal="false" overflowToDisk="true" timeToIdleSeconds="3600" timeToLiveSeconds="3600" memoryStoreEvictionPolicy="LFU" /></ehcache>

 

拦截代码具体实现:

/**
 * @Title: PageEhCacheFilter.java
 * @Package com.cqut.tool.cache
 * @Description: TODO(用一句话描述该文件做什么)
 * @author matao@cqrainbowsoft.com
 * @date 2014-8-1 上午12:29:00
 * @version V1.0
 */
package com.cqut.tool.cache;
import java.util.Enumeration;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.ehcache.CacheException;
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;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

 /**
 * 项目名称:<span style="font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;">SpringMVCDemo</span> 类名称:PageEhCacheFilter 类描述: 创建人:熊海 创建时间:2014-8-1
 * 上午12:29:00 修改人:熊海 修改时间:2014-8-1 上午12:29:00 修改备注:
 * 
 * @version 1.0 <span style="font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;">Superc102</span>
 */
public class PageEhCacheFilter extends SimplePageCachingFilter {
	private final static Logger log = Logger.getLogger(PageEhCacheFilter.class);
	private final static String FILTER_URL_PATTERNS = "patterns";
	private static String[] cacheURLs;
	private void init() throws CacheException {
		String patterns = filterConfig.getInitParameter(FILTER_URL_PATTERNS);
		cacheURLs = StringUtils.split(patterns, ",");
	}

	@Override
	protected void doFilter(final HttpServletRequest request,
	final HttpServletResponse response, final FilterChain chain)
	throws AlreadyGzippedException, AlreadyCommittedException,
	FilterNonReentrantException, LockTimeoutException, Exception {
		if (cacheURLs == null) {
			init();
		}
		String url = request.getRequestURI();
		boolean flag = false;
		if (cacheURLs != null && cacheURLs.length > 0) {
			for (String cacheURL : cacheURLs) {
				if (url.contains(cacheURL.trim())) {
					flag = true;
					break;
				}
			}
		}

		// 如果包含我们要缓存的url 就缓存该页面,否则执行正常的页面转向
		if (flag) {
			String query = request.getQueryString();
			if (query != null) {
				query = "?" + query;
			}
			log.info("当前请求被缓存:" + url + query);
			super.doFilter(request, response, chain);
		} else {
			chain.doFilter(request, response);
		}
	}

	@SuppressWarnings("unchecked")
	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)
	 * 
	 *      <b>function:</b> 兼容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;
	}

}

web.xml加入如下配置:

  <!-- ehcache页面缓存 -->
	<filter>
    	<filter-name>PageEhCacheFilter</filter-name>
   		<filter-class>com.cqut.tool.cache.PageEhCacheFilter</filter-class>
   		<init-param>
			<param-name>patterns</param-name>
			<!-- 配置你需要缓存的url -->
			<param-value>/module/jsp/news/newsCenter.jsp,indexPicController/getDimensionCode.do</param-value>
		</init-param>
   		       
	</filter>
	<filter-mapping>
		<filter-name>PageEhCacheFilter</filter-name>
	    <url-pattern>*.jsp</url-pattern>
	</filter-mapping>
	
	<filter-mapping>
		<filter-name>PageEhCacheFilter</filter-name>
	    <url-pattern>*.do</url-pattern>
	</filter-mapping>
测试页面:

<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%@ page import="com.cqut.tool.util.PropertiesTool"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+PropertiesTool.getSystemPram("serverName")+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'testcache.jsp' starting page</title>
    
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->

  </head>
  
  <body>
    <%=new Date() %>
  </body>
</html>

当第一次请求这些页面后,这些页面就会被添加到缓存中,如果缓存没失效的话以后请求这些页面将会从缓存中获取。
把缓存测试页面加入web.xml的配置中后。如果时间是变动的,则表示该页面没有被缓存或是缓存已经过期,否则则是在缓存状态了。

三、对象缓存

对象缓存就是将查询的数据添加到缓存中,下次再次查询相同东西的时候直接从缓存中获取,而不去数据库中查询。

对象缓存一般是针对方法、类而来的。本教程结合Spring的Aop对象、方法缓存来说明。

在application.xml的命名空间中加入下面配置:

xmlns:cache="http://www.springframework.org/schema/cache"

xmlns:p="http://www.springframework.org/schema/p"

http://www.springframework.org/schema/cache

http://www.springframework.org/schema/cache/spring-cache.xsd

在application.xml的中加入下面配置:

<!--start spring缓存 -->
<cache:annotation-driven /><!-- 支持缓存的配置项<span style="font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;">注解</span> -->
<!--start 一般的spring_ehcache缓存管理 -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>
<!-- EhCache library setup -->
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="classpath:ehcache.xml" p:shared="true"/> 
<!-- 保持使用p:shared="true"同一个缓存 -->
<!--end 一般的spring_ehcache缓存管理 -->
<!--end spring缓存 -->
java测试方法:

@Override
@Cacheable(value="myCache",key="#columnCode+'ColumnsServicegetColumns'",condition="#columnCode<23")
public String getColumns(int columnCode){
<pre name="code" class="html">	System.out.println("请求后台:"+columnCode);
        return "xhay";
<pre name="code" class="html">}

 
 

@Cacheable注解可以用在方法或者类级别。当他应用于方法级别的时候,就是如上所说的缓存返回值了。当应用在类级别的时候,这个类的所有方法的返回值都将被缓存。

@Cacheable注解有三个参数,value是必须的,还有key和condition。第一个参数,也就是value指明ehcache.xml配置的缓存名称。

@Cacheable注解的方法的签名来作为key,当然你可以重写key,自定义key可以使用SpEL表达式。

@Cacheable的最后一个参数是condition(可选),同样的,也是引用一个SpEL表达式。但是这个参数将指明方法的返回结果是否被缓存。


在上面这个测试例子中,第一次访问的时候后台会打印日志“请求后台:”,下一次请求的时候直接从缓存中拿数据。不会有后台输出。


想对EhCache做进一步了解的可以参考这一片文章:http://raychase.iteye.com/blog/1545906

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值