1.技术背景:java
系统缓存是位于应用程序与物理数据源之间,用于临时存放复制数据的内存区域,目的是为减小应用程序对物理数据源访问的次数,从而提升应用程序的运行性能。缓存设想内存是有限的,缓存的时效性也是有限的,因此能够设定内存数量的大小能够执行失效算法,能够在内存满了的状况下,按照最少访问等算法将缓存直接移除或切换到硬盘上。web
Ehcache从Hibernate发展而来,逐渐涵盖了Cache界的所有功能,是目前发展势头最好的一个项目,具备快速、简单、低消耗、扩展性强、支持对象或序列化缓存,支持缓存或元素的失效,提供LRU、LFU和FIFO缓存策略,支持内存缓存和硬盘缓存和分布式缓存机制等特色。其中Cache的存储方式为内存或磁盘(ps:无须担忧容量问题)算法
2.EhCahe的类层次介绍:sql
主要分为三层,最上层是CacheManager,它是操做Ehcache的入口。能够经过CacheManager.getInstance()得到一个单子的CacheManager,或者经过CacheManager的构造函数建立一个新的CacheManager。每一个CacheManger都管理多个Cache。每一个Cache都以一种类Hash的方式,关联多个Element。Element就是咱们用于存放缓存内容的地方。数据库
3.环境搭建:浏览器
很简单只须要将ehcache-2.1.0-distribution.tar.gz和ehcache-web-2.0.2-distribution.tar.gz挤压的jar包放入WEB-INF/lib下。缓存
再建立一个重要的配置文件ehcache.xml,能够从ehcache组件包中拷贝一个,也能够本身创建一个,须要放到classpath下,通常放于/WEB-INF/classed/ehcache.xml;具体的配置文件能够网上搜一下服务器
4.实际运用app
一个网站的首页估计是被访问次数最多的,咱们能够考虑给首页作一个页面缓存;框架
缓存策略:应该是某个固定时间以内不变的,好比说2分钟更新一次,以应用结构page-filter-action-service-dao-db为例。
位置:页面缓存作到尽可能靠近客户的地方,就是在page和filter之间,这样的优势就是第一个用户请求后,页面被缓存,第二个用户在请求,走到filter这个请求就结束了,须要在走到action-service-dao-db,好处固然是服务器压力大大下降和客户端页面响应速度加快。
首页页面缓存存活时间定为2分钟,也就是参数timeToLiveSeconds(缓存的存活时间)应该设置为120,同时timeToIdleSeconds(多长时间不访问缓存,就清楚该缓存)最好也设为2分钟或者小于2分钟。
接着咱们来看一下SimplePageCachingFilter 的配置,
<filter> <filter-name>indexCacheFilterfilter-name> <filter-class> net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter <filter-class> <filter> <filter-mapping> <filter-name>indexCacheFilterfilter-name> <url-pattern>*index.actionurl-pattern> <filter-mapping>
将上述代码加入到web.xml,那么当打开首页时,你会发现2分钟才会有一堆sql语句出如今控制台,也能够调整为5分钟,总之一切尽在掌控之中。
固然,若是你像缓存首页的部份内容时,你须要使用SimplePageFragmentCachingFilter这个filter,我看一下:
<filter> <filter-name>indexCacheFilterfilter-name> <filter-class> net.sf.ehcache.constructs.web.filter.SimplePageFragmentCachingFilter <filter-class> filter> <filter-mapping> <filter-name>indexCacheFilterfilter-name> <url-pattern>*/index_right.jsp<url-pattern> <filter-mapping>
如此咱们将jsp页面经过jsp:include到其余页面,这样就作到了页面局部缓存的效果,这一点貌似没有oscache的tag好用。
此外cachefilter中还有一个特性,就是gzip,也就是缓存中的元素是被压缩过的,若是客户端浏览器支持压缩的话,filter会直接返回压缩过的流,这样节省了带宽,把解压的工做交给了客户端浏览便可,固然若是客户端不支持gzip,那么filter会把缓存的元素拿出来解压后在返回给客户端浏览器(大多数爬虫是不支持gzip的,因此filter也会解压后在返回流)。
总之,Ehcache是一个很是轻量级的缓存实现,并且从1.2以后支持了集群,并且是hibernate默认的缓存provider,本文主要介绍Ehcahe对页面缓存的支持,可是它的功能远不止如此,要用好缓存,对J2ee中缓存的原理、适用范围、适用场景等等都须要比较深入的理解,这样才能用好用对缓存。
为了你们经过实际例子加深了解与场景运用,在奉献一个实例:
*在Spring中运用EhCache
适用任意一个现有开源Cache Framework,要求能够Cache系统中service或者DAO层的get/find等方法返回结果,若是数据更新(适用了Create/update/delete),则刷新cache中相应的内容。
根据需求,计划适用Spring AOP+enCache来实现这个功能,采用ehCache缘由之一就是Spring提供了enCache的支持,至于为什么仅仅支持ehcache而不支持oscache和jbosscache就无从得知了。
AOP少不了拦截器,先建立一个实现了MethodInterceptor接口的拦截器,用来拦截Service/DAO的方法调用,拦截到方法后,搜索该方法的结果在cache中是否存在,若是存在,返回cache中结果,若是不存在返回数据库查询结果,并将结果返回到缓存。
public class MethodCacheInterceptor implements MethodInterceptor, InitializingBean { private static final Log logger = LogFactory.getLog(MethodCacheInterceptor.class); private Cache cache; public void setCache(Cache cache) { this.cache = cache; } public MethodCacheInterceptor() { super(); } /** * 拦截Service/DAO 的方法,并查找该结果是否存在,若是存在就返回cache 中的值, * 不然,返回数据库查询结果,并将查询结果放入cache */ public Object invoke(MethodInvocation invocation) throws Throwable { String targetName = invocation.getThis().getClass().getName(); String methodName = invocation.getMethod().getName(); Object[] arguments = invocation.getArguments(); Object result; logger.debug("Find object from cache is " + cache.getName()); String cacheKey = getCacheKey(targetName, methodName, arguments); Element element = cache.get(cacheKey); Page 13 of 26 if (element == null) { logger.debug("Hold up method , Get method result and create cache........!"); result = invocation.proceed(); element = new Element(cacheKey, (Serializable) result); cache.put(element); } return element.getValue(); } /** * 得到cache key 的方法,cache key 是Cache 中一个Element 的惟一标识 * cache key 包括包名+类名+方法名,如com.co.cache.service.UserServiceImpl.getAllUser */ 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]); } } return sb.toString(); } /** * implement InitializingBean,检查cache 是否为空 */ public void afterPropertiesSet() throws Exception { Assert.notNull(cache, "Need a cache. Please use setCache(Cache) create it."); } }
上面的代码能够看到,在方法invoke中,完成了搜索cache/新建cache的功能
随后,再创建一个拦截器MethodCacheAfterAdvice,做用是在用户进行create/update/delete操做时来刷新、remove相关cache内容,这个拦截器须要实现AfterRetruningAdvice接口,将会在所拦截的方法执行后执行在afterReturning(object arg0,Method arg1,Object[] arg2,object arg3)方法中所预约的操做
public class MethodCacheAfterAdvice implements AfterReturningAdvice, InitializingBean { private static final Log logger = LogFactory.getLog(MethodCacheAfterAdvice.class); private Cache cache; Page 15 of 26 public void setCache(Cache cache) { this.cache = cache; } public MethodCacheAfterAdvice() { super(); } public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { String className = arg3.getClass().getName(); List list = cache.getKeys(); for(int i = 0;i<list.size();i++){ String cacheKey = String.valueOf(list.get(i)); if(cacheKey.startsWith(className)){ cache.remove(cacheKey); logger.debug("remove cache " + cacheKey); } } } public void afterPropertiesSet() throws Exception { Assert.notNull(cache, "Need a cache. Please use setCache(Cache) create it."); } }
该方法获取目标class的全名,如:com.co.cache.test.TestServiceImpl,而后循环cache的key list,刷新/remove cache中全部和该class相关的element。
接着就是配置encache的属性,如最大缓存数量、cache刷新的时间等等。
<ehcache> <diskStore path="c:\\myapp\\cache"/> <defaultCache maxElementsInMemory="1000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /> <cache name="DEFAULT_CACHE" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="300000" timeToLiveSeconds="600000" overflowToDisk="true" /> </ehcache>
这里须要注意的是defaultCache定义了一个默认的cache,这个Cache不能删除,不然会抛出No default cache is configured异常。另外因为使用拦截器来刷新Cache内容,所以在定义cache生命周期时能够定义较大的数值,timeToIdleSeconds="30000000",timeToLiveSeconds="6000000",好像还不够大?
而后再将Cache和两个拦截器配置到Spring的配置文件cache.xml中便可,须要建立两个“切入点”,分别用于拦截不一样方法名的方法。在配置application.xml而且导入cache.xml。这样一个简单的Spring+Encache框架就搭建完成。
因为时间关系就介绍到这里,之后有机会还会介绍Ehcache在分布式集群系统中的使用,谢谢你们。
转自:http://blog.csdn.net/yangchao228/article/details/7027485