一般在项目中都要用到缓存,比如hibernate一级、二级缓存,对象缓存,方法缓存,页面缓存,浏览器缓存等等。这里主要说下我在上个公司用到的使用ehcach方法缓存(分布式缓存)和simplepagecache页面缓存(需要改变tomcat启动编码),使用simplepagecache的目的是由于实现能够随时删除指定的页面缓存以及查看页面的访问次数。
下面首先说下方法缓存,看ehcache.xml文件。
[html] view plain copy print?
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<!--
maxElementsInMemory为缓存对象的最大数目,
eternal设置是否永远不过期,timeToIdleSeconds对象处于空闲状态的最多秒数,timeToLiveSeconds对象处于缓存状态的最多秒数
-->
<diskStore path="java.io.tmpdir" />
<cacheManagerEventListenerFactory class="" properties=""/>
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic,
multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446"/>
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/>
<defaultCache maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="60"
timeToLiveSeconds="60"
overflowToDisk="true" />
<cache name="org.hibernate.cache.StandardQueryCache"
maxElementsInMemory="5000"
eternal="false"
timeToIdleSeconds="180"
timeToLiveSeconds="180"
overflowToDisk="true" />
<cache name="org.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="true" />
<!--service层 方法缓存的数据过期策略 -->
<cache name="myCache"
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="1"
timeToLiveSeconds="1"
memoryStoreEvictionPolicy="LFU" />
<!--系统自定义 缓存的数据过期策略 永不过期 -->
<cache name="customerLongCache"
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="true"
timeToIdleSeconds="300000000"
timeToLiveSeconds="600000000"
memoryStoreEvictionPolicy="LFU" />
<!--设置user类的缓存的数据过期策略 -->
<cache name="net.b2c.u.model.UserU"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="2"
timeToLiveSeconds="2"
overflowToDisk="false"
memoryStoreEvictionPolicy="LFU" />
<!--页面缓存策略 -->
<cache name="SimplePageCachingFilter"
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="43200"
timeToLiveSeconds="43200"
memoryStoreEvictionPolicy="LFU">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"/>
</cache>
<!--主页缓存策略 --> <!-- 12小时 赞用于调用亿起发数据缓存策略-->
<cache name="yqfProductCache"
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="43200"
timeToLiveSeconds="43200"
memoryStoreEvictionPolicy="LFU" >
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"/>
</cache>
<cache name="yqfProductURLCache"
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="43200"
timeToLiveSeconds="43200"
memoryStoreEvictionPolicy="LFU" >
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"/>
</cache>
<cache name="yqfTptURLCache"
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="43200"
timeToLiveSeconds="43200"
memoryStoreEvictionPolicy="LFU">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"/>
</cache>
<cache name="shopcache"
maxElementsInMemory="300"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="43200"
timeToLiveSeconds="43200"
memoryStoreEvictionPolicy="LFU">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"/>
</cache>
</ehcache>
具体的每个配置意义我就不再详细说明,可以在网上查找,主要说下这里的每个cache,可以当成一个存放在内存中的map数据结构,有key,有value。
关键代码如下:
[java] view plain copy print?
package net.b2c.yqf.util;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
public class CacheUtil {
private static Cache cache =null;
private static Cache cacheUrl = null;
private static Cache chacheTuanUrl = null;
static {
// 使用默认配置文件创建CacheManager
CacheManager manager = CacheManager.create();
cache = manager.getCache("yqfProductCache");
cacheUrl = manager.getCache("yqfProductURLCache");
chacheTuanUrl = manager.getCache("yqfTptURLCache");
}
/**
* @param args
*/
public static void main(String[] args) {
//保存数据到cache中
Element element = new Element("key1", "value1");
cache.put(element);
//从cache中取回元素
Element element2 = getCache().get("key1");
element2.getValue();
//从Cache中移除一个元素
// cache.remove("key");
System.out.println(element2.getValue());
}
public static Cache getCache() {
return cache;
}
public static Cache getCacheUrl() {
return cacheUrl;
}
public static Cache getChacheTuanUrl() {
return chacheTuanUrl;
}
}
[java] view plain copy print?
/**
* 全部团购子目录
*/
public static List<TuanCategory> getCacheTuanGouCotegoryAll(){
List<TuanCategory> list = new ArrayList<TuanCategory>();
String mlKey = "tuangouzimuluall";
Cache cache = CacheUtil.getCache();
Element element = null;
synchronized (mlKey) {
element = cache.get(mlKey);
if(element!=null){
list = (List<TuanCategory>)element.getValue();
if(list == null){
List<TuanCategory> listResult = YQF. getTuanGouCotegory();
if(listResult!=null){
for (TuanCategory tuanCategory : listResult) {
if(!tuanCategory.getIsParent()){
list.add(tuanCategory);
}
}
Element elem = new Element(mlKey,list);
cache.put(elem);
}
}
}else{
List<TuanCategory> listResult = YQF. getTuanGouCotegory();
if(listResult!=null){
for (TuanCategory tuanCategory : listResult) {
if(!tuanCategory.getIsParent()){
list.add(tuanCategory);
}
}
Element elem = new Element(mlKey,list);
cache.put(elem);
}
}
}
return list;
}
相信大家一定都能看得懂上面的代码。
拦截指定方法的cache
[java] view plain copy print?
package net.b2c.u.interceptor;
import java.io.Serializable;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CacheIntercept {
private Logger logger= LoggerFactory.getLogger(getClass());
private Cache cache;
public Cache getCache() {
return cache;
}
public void setCache(Cache cache) {
this.cache = cache;
}
private String getCacheKey(String targetName, String methodName,
Object[] arguments) {
StringBuffer sb = new StringBuffer();
sb.append(targetName).append(".").append(methodName);
if ((arguments != null) && (arguments.length != 0)) {
for (int i = 0; i < arguments.length; i++) {
sb.append(".").append(arguments[i].toString());
}
}
return sb.toString();
}
public Object myCache(ProceedingJoinPoint pjp) throws Throwable
{
// System.out.println("maxSec:"+getMaxSecond());
String className = pjp.getTarget().getClass().getName();
String methodName=pjp.getSignature().getName();
Object[] args= pjp.getArgs();
String cacheKey = getCacheKey(className, methodName, args);
logger.info("mycache_query_cacheKey:"+cacheKey);
Element element = null;
Object result=null;
synchronized (cacheKey) {
element = cache.get(cacheKey);
if (element == null) {
logger.info("mycache_cacheKey_not_exist:"+cacheKey);
result = pjp.proceed(args);
logger.info("mycache_cache_result:"+result);
element = new Element(cacheKey, (Serializable) result);
cache.put(element);
}else{
logger.info("mycache_cacheKey_exist:"+cacheKey);
}
}
return result;
}
}
[html] view plain copy print?
<!-- 缓存配置 拦截器 -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"></bean>
<bean id="myCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager" ref="cacheManager" />
<property name="cacheName">
<value>myCache</value>
</property>
</bean>
<bean id="cacheInterceptor" class="net.b2c.u.interceptor.CacheIntercept">
<property name="cache">
<ref local="myCache"/>
</property>
</bean>
[html] view plain copy print?
<aop:config>
<aop:pointcut id="mypointcut"
expression="execution(public * net.b2c.u.service..*.*(..))" />
<aop:aspect id="cacheAspect" ref="cacheInterceptor">
<aop:around method="myCache" pointcut-ref="mypointcut"/>
</aop:aspect>
</aop:config>
下面说说simplepagecache,先看效果
配置:
[java] view plain copy print?
package net.b2c.u.interceptor;
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;
/**
*
* 页面缓存过滤器
*/
public class PageEhCacheFilter extends SimplePageCachingFilter {
private final static Logger log = Logger.getLogger(PageEhCacheFilter.class);
private final static String FILTER_URL_PATTERNS = "patterns";
private final static String NO="callback";
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();
// log.debug("url:"+url);
boolean flag = false;
if (cacheURLs != null && cacheURLs.length > 0) {
for (String cacheURL : cacheURLs) {
if (url.equals(cacheURL.trim())) {
flag = true;
break;
}
}
}
// 如果包含我们要缓存的url 就缓存该页面,否则执行正常的页面转向
if (flag) {
String query = request.getQueryString();
if (query != null) {
if(query.contains(NO))
{
chain.doFilter(request, response);
return;
}
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;
}
@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;
}
@Override
protected String calculateKey(HttpServletRequest httpRequest) {
StringBuffer stringBuffer = new StringBuffer();
String uri=httpRequest.getRequestURI();
String parram=httpRequest.getQueryString();
if(null == parram )parram="";
stringBuffer.append(uri).append(parram);
String key = stringBuffer.toString();
return key;
}
}
[html] view plain copy print?
<filter>
<filter-name>SimplePageCachingFilter</filter-name>
<filter-class>net.b2c.u.interceptor.PageEhCacheFilter</filter-class>
<init-param>
<param-name>patterns</param-name>
<param-value></param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SimplePageCachingFilter</filter-name>
<url-pattern>/</url-pattern>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.action</url-pattern>
</filter-mapping>
[html] view plain copy print?
<%@page import="java.util.Date"%>
<%@page import="net.sf.ehcache.Element"%>
<%@page import="net.sf.ehcache.constructs.blocking.BlockingCache"%>
<%@page import="net.sf.ehcache.CacheManager"%>
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%
String ctxpath = request.getContextPath();
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>页面缓存</title>
<link rel="stylesheet" type="text/css" href="../../css/demo_page.css" />
<link rel="stylesheet" type="text/css" href="../../css/demo_table.css" />
<script type="text/javascript" language="javascript" src="../../js/jquery-1.7.1.js"></script>
<script type="text/javascript" src="../../js/jquery.form.js"></script>
<style type="text/css">
.btr{border:1px solid #D9E7F8;border-collapse:collapse;}
</style>
</head>
<body id="dt_example" class="ex_highlight_row">
<br>
<%
CacheManager manager = CacheManager.create();
BlockingCache cache = new BlockingCache(manager.getEhcache("SimplePageCachingFilter"));
if(cache.getSize()>0){
%>
<table width="100%" align="center">
<tr><td align="center"><font size="4px">所有静态化页面</font></td></tr>
</table>
<br>
<table width="90%" align="center">
<tr>
<td width="20%">缓存中对象个数:<%=cache.getSize() %></td>
<td width="80%">缓存读取的命中次数:<%=cache.getStatistics().getCacheHits() %></td>
</tr>
<tr>
<td >缓存对象占用内存的大小:<%=cache.getMemoryStoreSize() %></td>
<td>缓存读取的错失次数:<%=cache.getStatistics().getCacheMisses() %></td>
</tr>
</table>
<br>
<table width="90%" class="btr" align="center">
<tr class="btr">
<th width="10%" class="btr">序号</th>
<th width="30%" class="btr">缓存页面</th>
<th width="10%" class="btr">访问次数</th>
<th width="15%" class="btr">缓存时间</th>
<th width="15%" class="btr">过期时间</th>
<th width="20%" class="btr">操作</th>
</tr>
<%
int i = 0;
for(Object obj:cache.getKeysWithExpiryCheck()){
i++;
Element el=cache.getQuiet(obj);
%>
<tr class="btr">
<td class="btr" align="center"><%=i %></td>
<td class="btr" align="center"><%=obj %></td>
<td class="btr" align="center"><%=el.getHitCount() %></td>
<td class="btr" align="center"><%=new Date(el.getCreationTime()).toLocaleString() %></td>
<td class="btr" align="center"><%=new Date(el.getExpirationTime()).toLocaleString() %></td>
<td class="btr" align="center">
<input type="button" value="清 楚 缓 存" οnclick="clearCache('<%=obj %>');">
</td>
</tr>
<%}%>
</table>
<%}else{ %>
<table width="100%" align="center" height="50px">
<tr><td align="center"><font size="5px">当前无缓存页面.....</font></td></tr>
</table>
<%}%>
</body>
<script type="text/javascript">
function clearCache(obj){
if(window.confirm("你确认清楚该页面缓存吗?")){
$.ajax({
dataType : 'json',
url : "auser2!remouveCahce.action",
cache : false,
type : 'POST',
data:{
"userName":obj
},
success : function(data) {
if(data == "1"){
alert("清出成功!");
window.location.reload();
}
},
error : function(XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus);
}
});
}
}
</script>
</html>
action
[java] view plain copy print?
//清出
public void remouveCahce() throws IOException{
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
String urls = this.getUserName().toString();
CacheManager manager = CacheManager.create();
BlockingCache cache = new BlockingCache(manager.getEhcache("SimplePageCachingFilter"));
for(Object obj:cache.getKeys()){
if(obj.toString().matches(urls)){
cache.remove(obj);
}
}
response.getWriter().write(new Gson().toJson("1"));
}