锁定老帖子 主题:Spring3.1.M1 Cache注解
精华帖 (0) :: 良好帖 (5) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-08-26
最后修改:2011-08-28
需要感慨一下,spring3.0时丢弃了2.5时的spring-modules-cache.jar,致使无法使用spring来方便的管理cache注解,好在3.1.M1中增加了对cache注解的支持,可喜可贺啊!
希望了解spring2.5的cache注解,可以参考如下内容: Spring基于注解的缓存配置--EHCache AND OSCacheSpring基于注解的缓存配置--web应用实例2.5时,spring没有自己的解决方案,都是采用对许多第三方cache框架的支持,比如EHCache和OSCache等等,不过到了3.1,spring就只提供EHCache的支持了,不过spring3.1还给出了自己的解决方案。
下面简单介绍一下spring3.1.M1中的cache功能。 spring3.1.M1中负责cache的模块是org.springframework.context-3.1.0.M1.jar
与2.5时的modules模块类似,3.1的注解缓存也是在方法上声明注解,3.1同样提供了两个注解: @Cacheable:负责将方法的返回值加入到缓存中 @CacheEvict:负责清除缓存
@Cacheable 支持如下几个参数: value:缓存位置名称,不能为空,如果使用EHCache,就是ehcache.xml中声明的cache的name key:缓存的key,默认为空,既表示使用方法的参数类型及参数值作为key,支持SpEL condition:触发条件,只有满足条件的情况才会加入缓存,默认为空,既表示全部都加入缓存,支持SpEL
例如: //将缓存保存进andCache,并使用参数中的userId加上一个字符串(这里使用方法名称)作为缓存的key @Cacheable(value="andCache",key="#userId + 'findById'") public SystemUser findById(String userId) { SystemUser user = (SystemUser) dao.findById(SystemUser.class, userId); return user ; } //将缓存保存进andCache,并当参数userId的长度小于32时才保存进缓存,默认使用参数值及类型作为缓存的key @Cacheable(value="andCache",condition="#userId.length < 32") public boolean isReserved(String userId) { System.out.println("hello andCache"+userId); return false; }
@CacheEvict 支持如下几个参数: value:缓存位置名称,不能为空,同上 key:缓存的key,默认为空,同上 condition:触发条件,只有满足条件的情况才会清除缓存,默认为空,支持SpEL allEntries:true表示清除value中的全部缓存,默认为false
例如: //清除掉指定key的缓存 @CacheEvict(value="andCache",key="#user.userId + 'findById'") public void modifyUserRole(SystemUser user) { System.out.println("hello andCache delete"+user.getUserId()); } //清除掉全部缓存 @CacheEvict(value="andCache",allEntries=true) public final void setReservedUsers(String[] reservedUsers) { System.out.println("hello andCache deleteall"); }
一般来说,我们的更新操作只需要刷新缓存中某一个值,所以定义缓存的key值的方式就很重要,最好是能够唯一,因为这样可以准确的清除掉特定的缓存,而不会影响到其它缓存值 , 比如我这里针对用户的操作,使用(userId+方法名称)的方式设定key值 ,当然,你也可以找到更适合自己的方式去设定。
SpEL:Spring Expression Language 关于SpEL的介绍,可以参考如下地址: http://static.springsource.org/spring/docs/3.1.0.M1/spring-framework-reference/html/expressions.html
了解了cache的注解之后,接下来说说如何使注解生效,其实就是需要在spring的配置文件中增加一些配置。
1.spring-cache 首先我们来看一下如何使用spring3.1自己的cache, 需要在命名空间中增加cache的配置 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd">
之后添加如下声明: <!-- 启用缓存注解功能,这个是必须的,否则注解不会生效,另外,该注解一定要声明在spring主配置文件中才会生效 --> <cache:annotation-driven cache-manager="cacheManager"/> <!-- spring自己的换管理器,这里定义了两个缓存位置名称 ,既注解中的value --> <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> <property name="caches"> <set> <bean class="org.springframework.cache.concurrent.ConcurrentCacheFactoryBean" p:name="default" /> <bean class="org.springframework.cache.concurrent.ConcurrentCacheFactoryBean" p:name="andCache" /> </set> </property> </bean>
2.spring-ehcache 接下来说说对ehcache的支持,其实只需要把cacheManager换成EHCache的cacheManager即可,如下: <!-- 启用缓存注解功能,这个是必须的,否则注解不会生效,另外,该注解一定要声明在spring主配置文件中才会生效 --> <cache:annotation-driven cache-manager="cacheManager"/> <!-- cacheManager工厂类,指定ehcache.xml的位置 --> <bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="classpath:/config/ehcache.xml" /> <!-- 声明cacheManager --> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="cacheManagerFactory" /> ehcache.xml <?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="java.io.tmpdir" /> --> <diskStore path="E:/cachetmpdir"/> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> <cache name="andCache" maxElementsInMemory="10000" maxElementsOnDisk="1000" eternal="false" overflowToDisk="true" diskSpoolBufferSizeMB="20" timeToIdleSeconds="300" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LFU" /> </ehcache>
ok,这样注解缓存就生效了。 附件中是我自己写的一个小例子,工程结构如下所示,运行com.piaoyi.function.demo下的DemoTest即可.
参考资料: http://blog.springsource.com/2011/02/23/spring-3-1-m1-caching/ http://hi.baidu.com/coolcooldool/blog/item/3b541533c72b40e21a4cffda.html
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-08-26
不需要再配置什么拦截器之类了哇?
执行该方法时会默认根据cache key查找吧?这部分没有提到呢。 |
|
返回顶楼 | |
发表时间:2011-08-26
CodeDestiny 写道 不需要再配置什么拦截器之类了哇?
执行该方法时会默认根据cache key查找吧?这部分没有提到呢。 因为使用注解,spring会自动对注解进行拦截,所以不需要额外配置拦截器,但如果希望基于aop进行拦截,可以自己声明拦截器,不过个人感觉注解的方便些。 方法被执行后,如果下次调用方法的参数没有变化,则不会在调用方法,直接从缓存中查找,查找规则就是这个key,默认是参数值,自己重新指定key,就是避免不同方法使用相同的参数时对缓存会造出干扰,另外刷新时也可以精确匹配到要刷新的数据 |
|
返回顶楼 | |
发表时间:2011-08-27
hanqunfeng 写道 CodeDestiny 写道 不需要再配置什么拦截器之类了哇?
执行该方法时会默认根据cache key查找吧?这部分没有提到呢。 因为使用注解,spring会自动对注解进行拦截,所以不需要额外配置拦截器,但如果希望基于aop进行拦截,可以自己声明拦截器,不过个人感觉注解的方便些。 方法被执行后,如果下次调用方法的参数没有变化,则不会在调用方法,直接从缓存中查找,查找规则就是这个key,默认是参数值,自己重新指定key,就是避免不同方法使用相同的参数时对缓存会造出干扰,另外刷新时也可以精确匹配到要刷新的数据 spring是怎样进行自动拦截的,我觉得说一下这块的代码,大家都会比较清楚吧,不然仅仅是配置,不够深入呀。 |
|
返回顶楼 | |
发表时间:2011-08-29
hanqunfeng 写道 CodeDestiny 写道 不需要再配置什么拦截器之类了哇?
执行该方法时会默认根据cache key查找吧?这部分没有提到呢。 因为使用注解,spring会自动对注解进行拦截,所以不需要额外配置拦截器,但如果希望基于aop进行拦截,可以自己声明拦截器,不过个人感觉注解的方便些。 方法被执行后,如果下次调用方法的参数没有变化,则不会在调用方法,直接从缓存中查找,查找规则就是这个key,默认是参数值,自己重新指定key,就是避免不同方法使用相同的参数时对缓存会造出干扰,另外刷新时也可以精确匹配到要刷新的数据 支持集群吗?集群情况下是怎么刷新的?oscache刷新只能按group,比较烦。 |
|
返回顶楼 | |
发表时间:2011-08-29
@Cacheable(value="andCache",key="#userId + 'findById'")
如果key除了userId还需要别的信息怎么办? |
|
返回顶楼 | |
发表时间:2011-08-29
JE帐号 写道 @Cacheable(value="andCache",key="#userId + 'findById'")
如果key除了userId还需要别的信息怎么办? 缓存是基于方法的,所以key就相当于要给你的方法起了一个唯一的名字,多个参数时可以自己拼装key,只要符合spel语法就行,比如:key="#userId + #user.username + 'findById'" ,但如果参数很多时,特别是封装对象很多时,要找出他们的唯一性还挺麻烦的,所以在设计需要缓存的方法时,需要特别注意参数的设计。这点,欢迎大家讨论。 |
|
返回顶楼 | |
发表时间:2011-08-29
比如我缓存了一个userList,但是此时我修改一个User,如何刷新userList缓存?
|
|
返回顶楼 | |
发表时间:2011-08-30
Jiagoo 写道 比如我缓存了一个userList,但是此时我修改一个User,如何刷新userList缓存?
举例: 1.增加userList缓存 @Cacheable(value="andCache",key="'ClassName'+'getUserList'") public List<SystemUser> getUserList() { List<SystemUser> userList = dao.getUserList(); return userList; } 2.清除userList缓存 @CacheEvict(value="andCache",key="'ClassName'+'getUserList'") public void modifyUser(SystemUser user) { dao.update(user); } 在你需要缓存结果集的方法上面增加@Cacheable注解,并给其起个key值,当方法第一次执行后缓存既生效,下次执行时则不会再执行方法体。 在你需要刷新缓存的方法上面增加@CacheEvict注解,并通过key定位到要清除的缓存,这里每当你执行 modifyUser方法后,都会清除掉userList缓存,也就是说,再次调用getUserList方法时会执行方法体。 |
|
返回顶楼 | |
发表时间:2011-12-22
hanqunfeng 写道 Jiagoo 写道 比如我缓存了一个userList,但是此时我修改一个User,如何刷新userList缓存?
举例: 1.增加userList缓存 @Cacheable(value="andCache",key="'ClassName'+'getUserList'") public List<SystemUser> getUserList() { List<SystemUser> userList = dao.getUserList(); return userList; } 2.清除userList缓存 @CacheEvict(value="andCache",key="'ClassName'+'getUserList'") public void modifyUser(SystemUser user) { dao.update(user); } 在你需要缓存结果集的方法上面增加@Cacheable注解,并给其起个key值,当方法第一次执行后缓存既生效,下次执行时则不会再执行方法体。 在你需要刷新缓存的方法上面增加@CacheEvict注解,并通过key定位到要清除的缓存,这里每当你执行 modifyUser方法后,都会清除掉userList缓存,也就是说,再次调用getUserList方法时会执行方法体。 我想他的意思是这个样子的: 我已经缓存了 一个list里面有5个user, 现在我修改了一个user1 但是我要刷新缓存的时候我只把user1替换了,而list的其他user没有替换,而不是重新加载一次list 请问这样子怎么解决? |
|
返回顶楼 | |