Spring集成ehcache
2016-03-10 16:38
399 查看
我的环境是:ehcache-2.10.1.jar,spring4.0.6。
1.首先要准备好Jar包
从http://www.ehcache.org/下载,如果是maven的话:
2.接下来配置spring xml:
3.配置ehcache.xml,我在spring xml中设置了ehcache.xml的位置在src某目录下:
4.接下来是编写我们的拦截器了,注意我的拦截器的包和你拦截器所在的包不一样,请在spring xml里做修改。
对于某一些特别的,不符合我们命名规范的方法,我们不想写在拦截器里,但是却想缓存对它进行处理。那么我们需要对相应的实现类(不是接口)进行注解:
@Cacheable(value=”daoCache”)注解表示我们需要缓存它,一般的我们会设置一个key值来确保其在缓存中更好的使用。
@CacheEvict(value=”daoCache”,allEntries=true) 注解表示我们需要清理缓存,allEntries=true表示清理全部缓存。
详情请看spring注解方面的文档。
需要注意的是,如果没有配置keyGenerator,那么Cacheable的默认key是”“,这样的话就必须手工指定一个了。
userKeyGenerator是我们自己的类:
1.首先要准备好Jar包
从http://www.ehcache.org/下载,如果是maven的话:
<dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.10.1</version> <type>pom</type> </dependency>
2.接下来配置spring xml:
<!-- 配置ehcache --> <!-- 开启ehcache注解 --> <cache:annotation-driven cache-manager="cacheManager" /> <bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="classpath:ehcache.xml" /> </bean> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"> <property name="cacheManager" ref="cacheManagerFactory" /> </bean> <bean id="ehCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"> <property name="cacheManager"> <ref local="cacheManagerFactory" /> </property> <property name="cacheName"> <value>DEFAULT_CACHE</value> </property> </bean> <!-- 创建缓存、查询缓存的拦截器 --> <bean id="cacheMethodInterceptor" class="net.kehwa.tb.board.core.ehcache.CacheMethodInterceptor"> <property name="cache"> <ref local="ehCache" /> </property> </bean> <!-- 更新缓存、删除缓存的拦截器 --> <bean id="cacheAfterReturningAdvice" class="net.kehwa.tb.board.core.ehcache.CacheAfterReturningAdvice"> <property name="cache"> <ref local="ehCache" /> </property> </bean> <!-- 插入拦截器,确认调用哪个拦截器,拦截器拦截的方法名特点等,此处调用拦截器CacheMethodInterceptor --> <bean id="cachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <!-- 加入切面,切面为当执行完print方法后,在执行加入的切面 --> <property name="advice"> <ref local="cacheMethodInterceptor" /> </property> <property name="patterns"> <list> <!-- ### .表示符合任何单一字元 ### +表示符合前一个字元一次或多次 ### *表示符合前一个字元零次或多次 ### \Escape任何Regular expression使用到的符号 --> <!-- .*表示前面的前缀(包括包名),意思是表示getObject方法--> <value>.*query.*</value> <value>.*get.*</value> <value>.*find.*</value> </list> </property> </bean> <!-- 插入拦截器,确认调用哪个拦截器,拦截器拦截的方法名特点等,此处调用拦截器CacheAfterReturningAdvice --> <bean id="cachePointCutAdvice" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref local="cacheAfterReturningAdvice" /> </property> <property name="patterns"> <list> <!-- .*表示前面的前缀(包括包名),意思是updateObject方法--> <value>.*delete.*</value> <value>.*update.*</value> <value>.*add.*</value> <value>.*save.*</value> <value>.*edit.*</value> </list> </property> </bean> <!-- 代理工厂 org.springframework.aop.framework.ProxyFactoryBean 只拦截一个 --> <bean id="proxyFactory" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <!-- 说明调用接口bean名称 --> <property name="beanNames"> <list> <value>*Service</value> </list> </property> <!-- 说明拦截器bean名称 --> <property name="interceptorNames"> <list> <value>cachePointCut</value> <value>cachePointCutAdvice</value> </list> </property> </bean>
3.配置ehcache.xml,我在spring xml中设置了ehcache.xml的位置在src某目录下:
<?xml version="1.0" encoding="utf-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true" monitoring="autodetect"> <diskStore path="d:/cachetmpdir" /> <!-- java.io.tmpdir 默认临时文件路径 user.dir 用户当前工作目录 user.home 用户主目录 --> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="30" timeToLiveSeconds="30" overflowToDisk="false" /> <cache name="daoCache" maxElementsInMemory="10000" maxElementsOnDisk="1000" eternal="false" overflowToDisk="true" diskSpoolBufferSizeMB="20" timeToIdleSeconds="300" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LFU" /> <!-- name:缓存名称。通常为缓存对象的类名(非严格标准)。 maxElementsInMemory:设置基于内存的缓存可存放对象的最大数目。 maxElementsOnDisk:设置基于硬盘的缓存可存放对象的最大数目。 eternal:如果为true,表示对象永远不会过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds属性,默认为false; timeToIdleSeconds: 设定允许对象处于空闲状态的最长时间,以秒为单位。当对象自从最近一次被访问后,如果处于空闲状态的时间超过了timeToIdleSeconds属性值, 这个对象就会过期。当对象过期,EHCache将把它从缓存中清空。只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限期地处于空闲状态。 timeToLiveSeconds:设定对象允许存在于缓存中的最长时间,以秒为单位。当对象自从被存放到缓存中后,如果处于缓存中的时间超过了 timeToLiveSeconds属性值, 这个对象就会过期。当对象过期,EHCache将把它从缓存中清除。只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限期地存在于缓存中。 timeToLiveSeconds必须大于timeToIdleSeconds属性,才有意义。 overflowToDisk:如果为true,表示当基于内存的缓存中的对象数目达到了maxElementsInMemory界限后,会把益出的对象写到基于硬盘的缓存中。 注意:如果缓存的对象要写入到硬盘中的话,则该对象必须实现了Serializable接口才行。 memoryStoreEvictionPolicy:缓存对象清除策略。有三种: 1 FIFO ,first in first out ,这个是大家最熟的,先进先出,不多讲了 2 LFU , Less Frequently Used ,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存。 2 LRU ,Least Recently Used ,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了, 而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。 --> </ehcache>
4.接下来是编写我们的拦截器了,注意我的拦截器的包和你拦截器所在的包不一样,请在spring xml里做修改。
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; import net.sf.ehcache.Cache; import net.sf.ehcache.Element; public class CacheMethodInterceptor implements MethodInterceptor, InitializingBean { private Cache cache; public void setCache(Cache cache) { this.cache = cache; } public CacheMethodInterceptor() { super(); } /** * 拦截ServiceManager的方法,并查找该结果是否存在,如果存在就返回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; // 创建一个字符串,用来做cache中的key String cacheKey = getCacheKey(targetName, methodName, arguments); // 从cache中获取数据 Element element = cache.get(cacheKey); if (element == null) { // 如果cache中没有数据,则查找非缓存,例如数据库,并将查找到的放入cache result = invocation.proceed(); // 生成将存入cache的key和value element = new Element(cacheKey, result); System.out.println(cacheKey + "-----进入非缓存中查找,例如直接查找数据库,查找后放入缓存"); // 将key和value存入cache cache.put(element); } else { // 如果cache中有数据,则查找cache System.out.println(cacheKey + "-----进入缓存中查找,不查找数据库,缓解了数据库的压力"); } return element.getObjectValue(); } /** * 获得cache的key的方法,cache的key是Cache中一个Element的唯一标识, * 包括包名+类名+方法名,如:com.test.service.TestServiceImpl.getObject */ 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是否为空 70 * 此方法会在所有属性都set之后调用 */ public void afterPropertiesSet() throws Exception { Assert.notNull(cache, "Need a cache. Please use setCache(Cache) create it."); } }
// 接下来是清除缓存的 package net.kehwa.tb.board.core.ehcache; import java.lang.reflect.Method; import java.util.List; import net.sf.ehcache.Cache; import org.springframework.aop.AfterReturningAdvice; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; public class CacheAfterReturningAdvice implements AfterReturningAdvice, InitializingBean { private Cache cache; public void setCache(Cache cache) { this.cache = cache; } public CacheAfterReturningAdvice() { 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); } } System.out.println("-----清除缓存"); } public void afterPropertiesSet() throws Exception { Assert.notNull(cache, "Need a cache. Please use setCache(Cache) create it."); } }
对于某一些特别的,不符合我们命名规范的方法,我们不想写在拦截器里,但是却想缓存对它进行处理。那么我们需要对相应的实现类(不是接口)进行注解:
@Cacheable(value="daoCache") public List<CyclicalLife> totalCyclicalLifeForm(String date) { return cycDao.totalCyclicalLifeForm(date); }
@Cacheable(value=”daoCache”)注解表示我们需要缓存它,一般的我们会设置一个key值来确保其在缓存中更好的使用。
@CacheEvict(value=”daoCache”,allEntries=true) 注解表示我们需要清理缓存,allEntries=true表示清理全部缓存。
注解名 | 描述 |
---|---|
Cacheable | Annotation indicating that the result of invoking a method (or all methods in a class) can be cached. |
CacheConfig | @CacheConfig provides a mechanism for sharing common cache-related settings at the class level. |
CacheEvict | Annotation indicating that a method (or all methods on a class) triggers a cache evict operation. |
CachePut | Annotation indicating that a method (or all methods on a class) triggers a cache put operation. |
Caching | Group annotation for multiple cache annotations (of different or the same type). |
EnableCaching | Enables Spring’s annotation-driven cache management capability, similar to the support found in Spring’s XML namespace. |
需要注意的是,如果没有配置keyGenerator,那么Cacheable的默认key是”“,这样的话就必须手工指定一个了。
<bean id="userKeyGenerator" class="net.kehwa.tb.board.core.ehcache.UserKeyGenerator" /> <cache:annotation-driven cache-manager="cacheManager" key-generator="userKeyGenerator"/>
userKeyGenerator是我们自己的类:
package net.kehwa.tb.board.core.ehcache; import java.lang.reflect.Method; import org.springframework.cache.interceptor.KeyGenerator; public class UserKeyGenerator implements KeyGenerator { @Override public Object generate(Object target, Method method, Object... params) { // 获取要拦截的类 String targetName = target.getClass().getName(); // 获取要拦截的类的方法 String methodName = method.getName(); StringBuffer sb = new StringBuffer(); sb.append(targetName).append(".").append(methodName); if ((params != null) && (params.length != 0)) { for (int i = 0; i < params.length; i++) { sb.append(".").append(params[i]); } } return sb.toString(); } }
相关文章推荐
- Java第一次实验要求
- Java集合类详解
- Java实现用传统分治法解决矩阵相乘问题
- java中 == 与 equal 的区别
- Eclipse构建Maven项目
- java泛型
- Java实现ZIP打包
- Android项目由Eclipse到Android Studio的完美迁移(包含友盟分享、百度统计、ViewPagerIndicat等第三方库文件、Jar包等)——项目迁移二
- Java调用WebService接口实现发送手机短信验证码功能,java 手机验证码,WebService接口调用
- JAVA - HashMap和HashTable
- java类与对象
- Eclipse 中搜索时快速索引
- mac 10.9下安装jdk8
- 基于java在服务端解决手机上传竖拍照片旋转90度问题
- Java 反射小用
- 如何在Spring容器中加载自定义的配置文件
- JAVA BigInteger(大数类)HDU 1002 1042
- java servlet 技术
- 查看Java程序运行时间
- struts2 jar包导入Unable to load configuration. - bean问题原因及解决办法