略
简介
缓存(Caching)可以存储经常用到的信息,这样每次需要的时候,这些信息都可以立即使用.尽管Spring自身没有实现缓存解决方案,但是它对缓存功能提供了声明式的支持,能够与多种流行的缓存进行集成.
启用对缓存的支持
Spring对缓存有两种支持方式:
- 注解驱动的缓存
- XML声明的缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheManager" id="cacheManager"/>
<cache:annotation-driven cache-manager="cacheManager"/>
</beans>
|
缓存管理器
Spring3.1中有5个:
- SimpleCacheManager
- NoOpCacheManger
- ConcurrentMapCacheManager
- CompositeCacheManager
- EhCacheCacheManager
Spring3.2后加入了:
- RedisCacheManager
- GemfireCacheManager
对与缓存管理器,有很多种方案可以选择,这里介绍EhCacheCacheManager.
使用Ehcache缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <bean id="EhCacheCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="classpath:ehcache.xml"/> </bean>
<bean id="EhCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"> <property name="cacheManager" ref="EhCacheCacheManager"/> </bean>
<cache:annotation-driven cache-manager="EhCacheManager"/>
</beans>
|
注意: 这里可能有这样的疑问,EhCacheManager的class是一个EhCacheManagerFactoryBean类型,为什么可以注入到EhCacheCacheManager中的cacheManager属性中去?
解释为:Spring提供了EhCacheManagerFactoryBean来产生CacheManager,因为它是一个工厂Bean ,它的ehcache()方法(我看源码是getObject()方法,<<Spring实战>>写错了???)可以创建并返回一个CacheManger实例,所以注册在Spring应用上下文中的并不是EhCacheManagerFactoryBean对象,而是CacheManger对象,因此适合注入到EhCacheCacheManager中.
ehcache.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" maxElementsOnDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> <persistence strategy="localTempSwap"/> </defaultCache> <cache name="bos" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" maxElementsOnDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> <persistence strategy="localTempSwap"/> </cache> </ehcache>
|
使用Redis缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="redisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="300"/> <property name="maxWaitMillis" value="3000"/> <property name="testOnBorrow" value="true"/> </bean> <bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName" value="localhost"/> <property name="port" value="6379"/> <property name="database" value="0"/> <property name="password" value="root"/> <property name="poolConfig" ref="redisPoolConfig"/> </bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="redisConnectionFactory"/> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> </bean> <bean class="org.springframework.data.redis.cache.RedisCacheManager" id="reidsCacheManager"> <constructor-arg ref="redisTemplate"/> </bean>
<cache:annotation-driven cache-manager="reidsCacheManager"/> </beans>
|
使用多个缓存管理器
Spring还支持配置多个缓存管理器,一起工作,通过迭代的方式,来查找之前所缓存的值,它会迭代JCacheCacheManager,EhCacheManager和RedisCacheManager.
1 2 3 4 5 6 7 8 9 10
| <bean id="manyCacheManager" class="org.springframework.cache.support.CompositeCacheManager"> <property name="cacheManagers"> <list> <ref bean="EhCacheManager"/> <ref bean="reidsCacheManager"/> </list> </property> </bean> <cache:annotation-driven cache-manager="manyCacheManager"/>
|
为方法添加注解来支持缓存
四个注解:
@Cacheable
表明Spring在调用方法前,首先应该在缓存中找该方法的返回值,如果这个值能够被找到,就会返回缓存的值,否则,会调用方法
@CachePut
表明Spring应该讲方法的返回值放到缓存中,在方法的调用前不会去检查缓存,方法始终会被调用.
@CacheEvict
表明Spring应该在缓存中清除一个或多个条目
@Caching
这是一个分组的注解,能够同时应用多个其他缓存注解(没用过,不知道)
解释一下2 : 就是该方法永远会被调用,不会走缓存,但是它会把返回值放到缓存中,给其他的方法用(无私奉献者)
填充注解
@Cacheable
和@CachePut
两个相似,它们的参数有:
- value—-缓存名,多个方法返回相同,业务允许的情况下,可以共用缓存名.
- condition—-spEL表达式,如果是false,不会将缓存放到方法调用上
- key—-spEL表达式,计算自定义的缓存key(就是查找缓存的索引)
- unless—–spEL表达式,如果是true,返回值不会放到缓存中
2表示,如果为false,该注解相当与没写,
4表示,如果为true,返回值不会赋给缓存
另外: key默认为参数(不写的话),所以有时候使用默认并不合适,手动设置key是很有必要的.
对于有复杂参数的方法,必须自定义key属性
自定义缓存key
Spring提供了多个用来定义缓存规则的SpEL拓展:
表达式 |
描述 |
#root.args |
传递给缓存方法的参数,形式为数组 |
#root.caches |
该方法执行时对应的缓存,形式为数组 |
#root.target |
目标对象 |
#root.targetClass |
目标对象的类,等于#root.target.class |
#root.method |
缓存方法 |
#root.methodName |
缓存方法的名字,等于#root.method.name |
#result |
方法的返回值(不能用于@Cacheable) |
#Argument |
任意的方法参数名(#argName)或参数索引(#a0或者#p0) |
条件化缓存
unless属性:如果是true,返回值不会放到缓存中,但是还是会在缓存中查找,找到就会走缓存.例如
1 2 3 4
| @Cacheable(value="name" unless="#result.message.contains('NoCache')" condition="#id >= 10") Spittle findOne(long id);
|
如果传入的id大于10,这个注解就相当于没写,如果返回结果中的message属性中包含"NoCache"
返回的结果就不会存到缓存中,如果不包含就会存到缓存中,当下次调用方式时,还是会走缓存,查询到缓存的值.
移出缓存条目
可用于移出指定的缓存,例如当执行remove()方法时就可以使用.
@CacheEvict
属性为:
- value—-缓存名称
- key—删除哪一个缓存
- condition—-不解释
- allEntries—boolean类型,如果为true,就删除所有目录
- beforeInvocation—boolean类型,如果为true,方法调用前删除条目,如果为false(默认),方法成功后再删除条目.
使用XML声明缓存
如果在自己代码上使用注解让你很不爽,
或者你需要在没有源码的bean上使用缓存功能.
这时就需要使用XML的方式.具体的XML写法,略(不想写,感觉用注解挺好的,结合aop自己猜怎么写XML).
元素 |
描述 |
<cache:annotation-driven> |
启用缓存 |
<cache:advice> |
定义缓存通知,结合<aop:advisor> ,将通知应用到切点上. |
<cache:caching> |
在缓存通知中,定义一组特定的缓存规则 |
<cache:cacheable> |
@Cacheable |
<cache:cache-put> |
@CachePut |
<cache:cache-evict> |
@CacheEvict |