缓存可以存储经常会用到的数据,spring对缓存提供了声明式的支持,能够与多种流行的缓存实现进行集成。spring使用缓存流程如下:
- 使用@EnableCaching启用缓存。
- 配置缓存管理器
- 为需要缓存的方法添加相关注解。
启用缓存
@EnableCaching
@Configuration
public class CacheConfig {
//缓存配置
}
配置缓存管理器
缓存管理器是spring缓存抽象的核心,它能够与多个流行的缓存实现进行集成。
spring3.1内置了5个缓存管理器
- SimpleCacheManager
- NoOpCacheManager
- ConcurrentMapCacheManager
- CompositeCacheManager
- EhChcheCaheManager
Spring3.2引入一个新的管理器,可基于JCache(JSR-107)的缓存提供商。Spring Data又提供了两个缓存管理器。
- RedisCacheManager(来自于Spring Data Redis项目)
- GemfireCacheManager(来自于Spring Data GemFire项目)
配置Redis缓存管理器
配置RedisConnectionFactory
- JedisConnectionFactory
- JredisConnectionFactory
- LettuceConnectionFactory
- SrpConnectionFactory
以JedisConnectionFactory为例,装配代码如下:
@Bean
public RedisConnectionFactory redisCF() {
JedisConnectionFactory cf = new LettuceConnectionFactory();
cf.setHostName("redis-server");
cf.setPort(7379);
cf.setPassword("foobared");
return cf;
}
如果使用其它链接工厂,只需要替换即可。
配置RedisTemplate
- RedisTemplate
- StringRedisTemplate
@Bean
public RedisTemplate<String, Product>
redisTemplate(RedisConnectionFactory cf) {
RedisTemplate<String, Product> redis =
new RedisTemplate<String, Product>();
redis.setConnectionFactory(cf);
return redis;
}
@Bean
public StringRedisTemplate
stringRedisTemplate(RedisConnectionFactory cf) {
return new StringRedisTemplate(cf);
}
RedisTemplate API:
方法 | 子API接口 | Description |
---|---|---|
opsForValue() | ValueOperations<K, V> | Operations for working with entries having simple values |
opsForList() | ListOperations<K, V> | Operations for working with entries having list values |
opsForSet() | SetOperations<K, V> | Operations for working with entries having set values |
opsForZSet() | ZSetOperations<K, V> | Operations for working with entries having ZSet (sorted set) values |
opsForHash() | HashOperations<K, HK, HV> | Operations for working with entries having hash values |
boundValueOps(K) | BoundValueOperations<K,V> | Operations for working with simple values bound to a given key |
boundListOps(K) | BoundListOperations<K,V> | Operations for working with list values bound to a given key |
boundSetOps(K) | BoundSetOperations<K,V> | Operations for working with set values bound to a given key |
boundZSet(K) | BoundZSetOperations<K,V> | Operations for working with ZSet (sorted set) values bound to a given key |
boundHashOps(K) | BoundHashOperations<K,V> | Operations for working with hash values bound to a given key |
设置key和value序列化器
当数据保存到redis中时,key和value都会使用序列化器进行序列化。Spring data redis提供了多个序列化器:
- GenericToStringSerializer —使用Spring转换服务进行序列化
- JacksonJsonRedisSerializer —使用Jackson 1,将对象序列化为JSON
- Jackson2JsonRedisSerializer —使用Jackson 2,将对象序列化为JSON
- JdkSerializationRedisSerializer —使用Java序列化
- OxmSerializer —使用Spring O/X映射的编排器和解排器(marshaler和unmarshaler)实 现序列化,用于XML序列化
- StringRedisSerializer —序列化String类型的key和value
@Bean
public RedisTemplate<String, Product>
redisTemplate(RedisConnectionFactory cf) {
RedisTemplate<String, Product> redis =
new RedisTemplate<String, Product>();
redis.setConnectionFactory(cf);
redis.setKeySerializer(new StringRedisSerializer());
redis.setValueSerializer(
new Jackson2JsonRedisSerializer<Product>(Product.class));
return redis;
}
package com.myapp;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.jedis
.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
//redis缓存管理器
return new RedisCacheManager(redisTemplate);
}
@Bean
public JedisConnectionFactory redisConnectionFactory() {
//连接工厂
JedisConnectionFactory jedisConnectionFactory =
new JedisConnectionFactory();
jedisConnectionFactory.afterPropertiesSet();
return jedisConnectionFactory;
}
@Bean
public RedisTemplate<String, String> redisTemplate(
RedisConnectionFactory redisCF) {
//redisTemplate bean
RedisTemplate<String, String> redisTemplate =
new RedisTemplate<String, String>();
redisTemplate.setConnectionFactory(redisCF);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
配置多个缓存管理器
@Bean
public CacheManager cacheManager(
net.sf.ehcache.CacheManager cm,
javax.cache.CacheManager jcm) {
CompositeCacheManager cacheManager = new CompositeCacheManager();
List<CacheManager> managers = new ArrayList<CacheManager>();
managers.add(new JCacheCacheManager(jcm));
managers.add(new EhCacheCacheManager(cm))
managers.add(new RedisCacheManager(redisTemplate()));
cacheManager.setCacheManagers(managers);
return cacheManager;
}
当查找缓存时,系统将依次通过JCacheCacheManager、EhCacheCacheManager、RedisCacheManager查找。
缓存注解
注解 | 描述 |
---|---|
@Cacheable |
表明
Spring在调用方法之前,首先应该在缓存中查找方法的返回值。如果这个值能够找到,就会返回缓存的值(不会调用方法)。否则的话,这个方法就会被调用,返回值会放到缓存之中(只能应用在返回值为非void的方法上)
|
@CachePut |
表明
Spring应该将方法的返回值放到缓存中。在方法的调用前并不会检查缓存,方法始终都会被调用(只能应用在返回值为非void的方法上)
|
@CacheEvict |
表明
Spring
应该在缓存中清除一个或多个数据(可以应用在返回值为void的方法上)
|
@Caching |
这是一个分组的注解,能够同时应用多个其他的缓存注解
|
@CacheConfig | 统一配置本类的缓存注解的属性,在类上面统一定义缓存的名字,方法上面就不用标注了,当标记在一个类上时则表示该类所有的方法都是支持缓存的 |
填充缓存
可以使用@Cacheable和CachePut进行缓存填充,需注意两者差别。
@Cacheable:表明Spring在调用方法之前,首先应该在缓存中查找方法的返回值。如果这个值能够找到,就会返回缓存的值(不会调用方法)。否则的话,这个方法就会被调用,返回值会放到缓存之中
@CachePut:表明Spring应该将方法的返回值放到缓存中。在方法的调用前并不会检查缓存,方法始终都会被调用
属性 | 类型 | 描述 |
---|---|---|
value、cacheNames | String[] | 要使用的缓存名称 |
condition | String |
SpEL
表达式,如果得到的值是
false
的话,不会将缓存应用到方法调用上
|
key | String |
SpEL
表达式,用来计算自定义的缓存
key
|
unless | String |
SpEL
表达式,如果得到的值是
true
的话,返回值不会放到缓存之中
|
keyGenerator | 用于指定key生成器,非必需。若需要指定一个自定义的key生成器,我们需要去实现org.springframework.cache.interceptor.KeyGenerator接口,并使用该参数来指定。需要注意的是:该参数与key是互斥的 | |
cacheManager | 用于指定使用哪个缓存管理器,非必需。只有当有多个时才需要使用 | |
cacheResolver | 用于指定使用那个缓存解析器,非必需。需通过org.springframework.cache.interceptor.CacheResolver接口来实现自己的缓存解析器,并用该参数指定。 |
当使用Spel表达式时,spring定义了一些供使用的元数据,如下:
表达式 | 描述 |
---|---|
#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和condition的差别
移除缓存
Attribute | Type | Description |
---|---|---|
value、cacheNames | String[] | 要使用的缓存名称 |
key | String |
SpEL
表达式,用来计算自定义的缓存
key
|
condition | String |
SpEL
表达式,如果得到的值是
false
的话,缓存不会应用到方法调用上
|
allEntries | boolean |
如果为
true
的话,特定缓存的所有条目都会被移除掉
|
beforeInvocation | boolean |
如果为
true
的话,在方法调用之前移除条目。如果为
false
(默认值)的话,在方
法成功调用之后再移除条目
|
注意
- 同一个类的a方法调用b方法,注解不生效。