论坛首页 Java企业应用论坛

Spring3.1.M1 Cache注解

浏览 13413 次
精华帖 (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 OSCache

Spring基于注解的缓存配置--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

 

 

 

 

  • 大小: 32.8 KB
   发表时间:2011-08-26  
不需要再配置什么拦截器之类了哇?
执行该方法时会默认根据cache key查找吧?这部分没有提到呢。
0 请登录后投票
   发表时间:2011-08-26  
CodeDestiny 写道
不需要再配置什么拦截器之类了哇?
执行该方法时会默认根据cache key查找吧?这部分没有提到呢。


因为使用注解,spring会自动对注解进行拦截,所以不需要额外配置拦截器,但如果希望基于aop进行拦截,可以自己声明拦截器,不过个人感觉注解的方便些。
方法被执行后,如果下次调用方法的参数没有变化,则不会在调用方法,直接从缓存中查找,查找规则就是这个key,默认是参数值,自己重新指定key,就是避免不同方法使用相同的参数时对缓存会造出干扰,另外刷新时也可以精确匹配到要刷新的数据
0 请登录后投票
   发表时间:2011-08-27  
hanqunfeng 写道
CodeDestiny 写道
不需要再配置什么拦截器之类了哇?
执行该方法时会默认根据cache key查找吧?这部分没有提到呢。


因为使用注解,spring会自动对注解进行拦截,所以不需要额外配置拦截器,但如果希望基于aop进行拦截,可以自己声明拦截器,不过个人感觉注解的方便些。
方法被执行后,如果下次调用方法的参数没有变化,则不会在调用方法,直接从缓存中查找,查找规则就是这个key,默认是参数值,自己重新指定key,就是避免不同方法使用相同的参数时对缓存会造出干扰,另外刷新时也可以精确匹配到要刷新的数据

spring是怎样进行自动拦截的,我觉得说一下这块的代码,大家都会比较清楚吧,不然仅仅是配置,不够深入呀。
0 请登录后投票
   发表时间:2011-08-29  
hanqunfeng 写道
CodeDestiny 写道
不需要再配置什么拦截器之类了哇?
执行该方法时会默认根据cache key查找吧?这部分没有提到呢。


因为使用注解,spring会自动对注解进行拦截,所以不需要额外配置拦截器,但如果希望基于aop进行拦截,可以自己声明拦截器,不过个人感觉注解的方便些。
方法被执行后,如果下次调用方法的参数没有变化,则不会在调用方法,直接从缓存中查找,查找规则就是这个key,默认是参数值,自己重新指定key,就是避免不同方法使用相同的参数时对缓存会造出干扰,另外刷新时也可以精确匹配到要刷新的数据

支持集群吗?集群情况下是怎么刷新的?oscache刷新只能按group,比较烦。
0 请登录后投票
   发表时间:2011-08-29  
@Cacheable(value="andCache",key="#userId + 'findById'") 

如果key除了userId还需要别的信息怎么办?
0 请登录后投票
   发表时间:2011-08-29  
JE帐号 写道
@Cacheable(value="andCache",key="#userId + 'findById'") 

如果key除了userId还需要别的信息怎么办?


缓存是基于方法的,所以key就相当于要给你的方法起了一个唯一的名字,多个参数时可以自己拼装key,只要符合spel语法就行,比如:key="#userId + #user.username + 'findById'" ,但如果参数很多时,特别是封装对象很多时,要找出他们的唯一性还挺麻烦的,所以在设计需要缓存的方法时,需要特别注意参数的设计。这点,欢迎大家讨论。
0 请登录后投票
   发表时间:2011-08-29  
比如我缓存了一个userList,但是此时我修改一个User,如何刷新userList缓存?
0 请登录后投票
   发表时间: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方法时会执行方法体。
0 请登录后投票
   发表时间: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

请问这样子怎么解决?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics