导言
从 Spring 1.1.1 开始,EHCache 就作为一种通用缓存解决方案集成进 Spring。
我将示范拦截器的例子,它能把方法返回的结果缓存起来。
利用 Spring IoC 配置 EHCache
在 Spring 里配置 EHCache 很简单。你只需一个 ehcache.xml 文件,该文件用于配置 EHCache:
<ehcache>
<!—设置缓存文件 .data 的创建路径。
如果该路径是 Java 系统参数,当前虚拟机会重新赋值。
下面的参数这样解释: user.home – 用户主目录 user.dir – 用户当前工作目录 java.io.tmpdir – 默认临时文件路径 --> <diskStore path="java.io.tmpdir"/>
<!—缺省缓存配置。CacheManager 会把这些配置应用到程序中。
下列属性是 defaultCache 必须的:
maxInMemory - 设定内存中创建对象的最大值。 eternal - 设置元素(译注:内存中对象)是否永久驻留。如果是,将忽略超 时限制且元素永不消亡。 timeToIdleSeconds - 设置某个元素消亡前的停顿时间。 也就是在一个元素消亡之前,两次访问时间的最大时间间隔值。 这只能在元素不是永久驻留时有效(译注:如果对象永恒不灭,则 设置该属性也无用)。 如果该值是 0 就意味着元素可以停顿无穷长的时间。 timeToLiveSeconds - 为元素设置消亡前的生存时间。 也就是一个元素从构建到消亡的最大时间间隔值。 这只能在元素不是永久驻留时有效。 overflowToDisk - 设置当内存中缓存达到 maxInMemory 限制时元素是否可写到磁盘 上。 -->
<cache name="org.taha.cache.METHOD_CACHE" maxElementsInMemory="300" eternal="false" timeToIdleSeconds="500" timeToLiveSeconds="500" overflowToDisk="true" /> </ehcache>
|
拦截器将使用 ”org.taha.cache.METHOD_CACHE” 区域缓存方法返回结果。下面利用 Spring IoC 让 bean 来访问这一区域。
<!-- ====================== 缓存 ======================= -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation"> <value>classpath:ehcache.xml</value> </property> </bean>
<bean id="methodCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"> <property name="cacheManager"> <ref local="cacheManager"/> </property> <property name="cacheName"> <value>org.taha.cache.METHOD_CACHE</value> </property> </bean>
|
构建我们的 MethodCacheInterceptor
该拦截器实现org.aopalliance.intercept.MethodInterceptor接口。一旦运行起来(kicks-in),它首先检查被拦截方法是否被配置为可缓存的。这将可选择性的配置想要缓存的 bean 方法。只要调用的方法配置为可缓存,拦截器将为该方法生成 cache key 并检查该方法返回的结果是否已缓存。如果已缓存,就返回缓存的结果,否则再次调用被拦截方法,并缓存结果供下次调用。
org.taha.interceptor.MethodCacheInterceptor
/* * Copyright 2002-2004 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
package org.taha.interceptor;
import java.io.Serializable;
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.Log;
import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert;
import net.sf.ehcache.Cache; import net.sf.ehcache.Element;
/** * @author <a href="mailto:irbouh@gmail.com">Omar Irbouh</a> * @since 2004.10.07 */ 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 void afterPropertiesSet() throws Exception { Assert.notNull(cache, "A cache is required. Use setCache(Cache) to provide one."); }
/** * 主方法 * 如果某方法可被缓存就缓存其结果 * 方法结果必须是可序列化的(serializable) */ 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("looking for method result in cache"); String cacheKey = getCacheKey(targetName, methodName, arguments); Element element = cache.get(cacheKey); if (element == null) { //call target/sub-interceptor logger.debug("calling intercepted method"); result = invocation.proceed();
//cache method result logger.debug("caching result"); element = new Element(cacheKey, (Serializable) result); cache.put(element); } return element.getValue(); }
/** * creates cache key: targetName.methodName.argument0.argument1... */ 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(); } }
|
MethodCacheInterceptor 代码说明了:
-
默认条件下,所有方法返回结果都被缓存了(methodNames 是 null)
-
缓存区利用 IoC 形成
-
cacheKey 的生成还包括方法参数的因素(译注:参数的改变会影响 cacheKey)
使用 MethodCacheInterceptor
下面摘录了怎样配置 MethodCacheInterceptor:
<bean id="methodCacheInterceptor" class="org.taha.interceptor.MethodCacheInterceptor"> <property name="cache"> <ref local="methodCache" /> </property> </bean>
<bean id="methodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref local="methodCacheInterceptor"/> </property> <property name="patterns"> <list> <value>.*methodOne</value> <value>.*methodTwo</value> </list> </property> </bean>
<bean id="myBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <bean class="org.taha.beans.MyBean"/> </property> <property name="interceptorNames"> <list> <value>methodCachePointCut</value> </list> </property> </bean>
|
译注
夏昕所著《Hibernate 开发指南》,其中他这样描述 EHCache 配置文件的:
<ehcache> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" //Cache中最大允许保存的数据数量 eternal="false" //Cache中数据是否为常量 timeToIdleSeconds="120" //缓存数据钝化时间 timeToLiveSeconds="120" //缓存数据的生存时间 overflowToDisk="true" //内存不足时,是否启用磁盘缓存 /> </ehcache> |
<ehcache> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" //Cache中最大允许保存的数据数量 eternal="false" //Cache中数据是否为常量 timeToIdleSeconds="120" //缓存数据钝化时间 timeToLiveSeconds="120" //缓存数据的生存时间 overflowToDisk="true" //内存不足时,是否启用磁盘缓存 /> </ehcache> |
<bean id="methodCacheInterceptor" class="org.taha.interceptor.MethodCacheInterceptor"> <property name="cache"> <ref local="methodCache" /> </property> </bean>
<bean id="methodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref local="methodCacheInterceptor"/> </property> <property name="patterns"> <list> <value>.*methodOne</value> <value>.*methodTwo</value> </list> </property> </bean>
<bean id="myBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <bean class="org.taha.beans.MyBean"/> </property> <property name="interceptorNames"> <list> <value>methodCachePointCut</value> </list> </property> </bean>
|
/* * Copyright 2002-2004 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
package org.taha.interceptor;
import java.io.Serializable;
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.Log;
import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert;
import net.sf.ehcache.Cache; import net.sf.ehcache.Element;
/** * @author <a href="mailto:irbouh@gmail.com">Omar Irbouh</a> * @since 2004.10.07 */ 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 void afterPropertiesSet() throws Exception { Assert.notNull(cache, "A cache is required. Use setCache(Cache) to provide one."); }
/** * 主方法 * 如果某方法可被缓存就缓存其结果 * 方法结果必须是可序列化的(serializable) */ 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("looking for method result in cache"); String cacheKey = getCacheKey(targetName, methodName, arguments); Element element = cache.get(cacheKey); if (element == null) { //call target/sub-interceptor logger.debug("calling intercepted method"); result = invocation.proceed();
//cache method result logger.debug("caching result"); element = new Element(cacheKey, (Serializable) result); cache.put(element); } return element.getValue(); }
/** * creates cache key: targetName.methodName.argument0.argument1... */ 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(); } }
|
<!-- ====================== 缓存 ======================= -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation"> <value>classpath:ehcache.xml</value> </property> </bean>
<bean id="methodCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"> <property name="cacheManager"> <ref local="cacheManager"/> </property> <property name="cacheName"> <value>org.taha.cache.METHOD_CACHE</value> </property> </bean>
|
<ehcache>
<!—设置缓存文件 .data 的创建路径。
如果该路径是 Java 系统参数,当前虚拟机会重新赋值。
下面的参数这样解释: user.home – 用户主目录 user.dir – 用户当前工作目录 java.io.tmpdir – 默认临时文件路径 --> <diskStore path="java.io.tmpdir"/>
<!—缺省缓存配置。CacheManager 会把这些配置应用到程序中。
下列属性是 defaultCache 必须的:
maxInMemory - 设定内存中创建对象的最大值。 eternal - 设置元素(译注:内存中对象)是否永久驻留。如果是,将忽略超 时限制且元素永不消亡。 timeToIdleSeconds - 设置某个元素消亡前的停顿时间。 也就是在一个元素消亡之前,两次访问时间的最大时间间隔值。 这只能在元素不是永久驻留时有效(译注:如果对象永恒不灭,则 设置该属性也无用)。 如果该值是 0 就意味着元素可以停顿无穷长的时间。 timeToLiveSeconds - 为元素设置消亡前的生存时间。 也就是一个元素从构建到消亡的最大时间间隔值。 这只能在元素不是永久驻留时有效。 overflowToDisk - 设置当内存中缓存达到 maxInMemory 限制时元素是否可写到磁盘 上。 -->
<cache name="org.taha.cache.METHOD_CACHE" maxElementsInMemory="300" eternal="false" timeToIdleSeconds="500" timeToLiveSeconds="500" overflowToDisk="true" /> </ehcache>
|
分享到:
相关推荐
Spring+EhCache缓存实例
spring + ehcache + redis两级缓存
(见下图,为了减少get这几条网络传输,我们会在每个应用服务器上增加本地的ehcache缓存作为二级缓存,即第一次get到的数据存入ehcache,后面output输出即可从本地ehcache中获取,不用再访问redis了,所以就减少了...
NULL 博文链接:https://liuyunlong1229.iteye.com/blog/2081421
配置ehcache缓存,存储内存的设置,与spring 的整合等
EhCache 是一个纯 Java 的进程内缓存框架,具有快速、精干等特点,是 Hibernate 中默认的 CacheProvider。Ehcache 是一种广泛使用的开源 Java 分布式缓存。主要面向通用缓存,Java EE 和轻量级容器。它具有内存和...
基于公司的项目在Spring中集成Ehcache,并提供EhcaheUtils工具类,并通过Spring的AOP编程实现方法缓存注解话,先奉献出核心代码,需要的朋友可以参考哦!
Spring与ehcache结合使用,本地缓存的实现
Ehcache 整合Spring 使用页面、对象缓存
需要使用Spring来实现一个Cache简单的解决方案,具体需求如下:使用任意一个现有开源Cache Framework,要求可以Cache系统中Service或则DAO层的get/find等方法返回结果,如果数据更新(使用Create/update/delete方法...
在Spring+Hibernate集成环境中使用EhCache缓存做的开发测试,在线程中打开数据库查询数据,及关闭数据库后查询数据的结果.
主要为大家详细介绍了Spring+EHcache缓存实例,EhCache是一个纯Java的进程内缓存框架,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
1.通过google ehcache-spring-annotatios.jar自动注解方式实现整合Spring+Ehcache。 2.Action里通过struts2-spring-plugin.jar插件自动根据名字注入。 3.Ajax无刷新异步调用Struts2,返回Json数据,以用户注册为例。...
缓存可以提高查询数据性能, 对同一批数据进行多次查询时, 第一次查询走数据库, 查询数据后,将数据保存在内存中,第二次以后查询 可以直接从内存获取数据,而不需要 和数据库进行交互。
当我们不指定具体其他第三方实现的时候,Spring Boot的Cache模块会使用ConcurrentHashMap来存储。而实际生产使用的时候,因为我们可能需要更多其他特性,往往就会采用其他缓存框架,所以接下来我们会分几篇分别介绍...
EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。 Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,...
【EhCache】Java缓存框架使用EhCache结合Spring AOP EhCache是一个纯Java的进程内缓存框架,具有如下特点: 1. 快速简单,非常容易和应用集成。 2.支持多种缓存策略 。 3. 缓存数据有两级:内存和磁盘,因此无需...
ehcache全解析 利用Spring和EHCache缓存结果 Hibernate+ehcache二级缓存技术 Spring基于注解的缓存配置--web应用实例 http://zjava.org.ru/
以java配置类方式 整合EhCache来实现页面整体缓存及页面局部缓存。详情见博客http://blog.csdn.net/poorCoder_/article/details/56483954