Spring Data Redis 包含了多个模版实现,用来完成Redis数据库的数据存储功能
但是为了创建spring data redis的模版,我们首先要有一个redis的连接工厂.
redis连接工厂会生成到redis数据库服务器的连接.spring data redis为四种redis客户端提供了链接工厂.
可自行选择链接工厂.
在做出决策后,我们就可以将连接工厂配置为 spring 中的bean.
@Bean
public RedisConnectionFactory redisCF(){
return new JedisConnectionFactory();
}
通过默认的构造器创建的连接工厂回想localhost上的6379端口创建连接,并且没有密码,如果你的redis运行在其他主机或者端口上,可使用链接工厂设置这些属性.
@Bean
public RedisConnectionFactory redisCF(){
JedisConnectionFactory cf = new JedisConnectionFactory();
cf.setHostName("192.168.80.155");
cf.setPort(6379);
return cf;
}
现在我们有了链接工厂,接下来皆可以使用spring data redis模版了
顾名思义,Redis连接工厂会生成到 redis key-value 的存储连接(以RedisConnection的形式).
借助connection我们就可以读取数据.
与其它的 spring data项目类似,spring data redis以模版的形式提供了较高等级的数据访问方案,实际上,有两个模版:
@Configuration
public class CacheConfig {
@Bean
public RedisConnectionFactory redisCF(){
JedisConnectionFactory cf = new JedisConnectionFactory();
cf.setHostName("192.168.80.155");
cf.setPort(6379);
return cf;
}
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory cf){
RedisTemplate template = new RedisTemplate();
template.setConnectionFactory(cf);
return template;
}
}
有了RedisTemplate之后,我们就可以操作key-value条目了,关于RedisTemplate的API,可以去网上详细查看
测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:spring-context.xml"})
public class CacheTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void test1(){
ValueOperations opsForValue = redisTemplate.opsForValue();
opsForValue.set("test1", "hello redis");
}
}
当某个条目保存到Redis key-value存储的时候,key和value都会使用redis的序列化器进行序列化.Spring data Redis提供了多个这样的序列化器.
* StringRedisSerializer 序列化String类型的key 和value
* GenericToStringSerializer 使用Spring转换器进行序列化.
* Jackson2JsonRedisSerializer 使用jackson2,将对象序列化为json
* JdkSerializationRedisSerializer 使用java序列化
* OxmSerializer 用于XML序列化
RedisTemplate 默认会使用 JdkSerializationRedisSerializer,这意味着key和value都会通过java进行序列化.
StringRedisTemplate 默认会使用 StringRedisSerializer ,这在我们意料之中.
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory cf){
RedisTemplate template = new RedisTemplate();
//key会被转换为String类型,非String类型会报错
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//设置序列化为 json的对象类型,必须实现 serializable接口
Jackson2JsonRedisSerializer
Spring 对缓存的支持有两者方式:
使用Spring的缓存抽象时,最为通用的方法就是在方法上添加 @Cacheable 注解 和 @CacheEvict 注解.
在往bean方法上添加缓存之前,必须先启用Spring对注解驱动缓存的支持.
如果我们使用java配置的话,可以在一个配置类上添加 @EnableCaching ,这样就能启用注解驱动的缓存
@Configuration
@EnableCaching
public class AnnoCacheConfig {
//声明缓存管理器
@Bean
public CacheManager cacheManager(){
CacheManager cacheManager = new ConcurrentMapCacheManager();
return cacheManager;
}
}
在上例中我们还声明了一个缓存管理器的bean.缓存管理器是Spring抽象的核心,它能够与多个流行的缓存实现进行集成
在本例中声明了 ConcurrentMapCacheManager,这个简单的缓存管理器,是基于内存的,所以它的声明周期是与应用相关联的,
幸好,有多个很棒的缓存管理器方案可供使用.
在为 Spring的缓存抽象选择管理器时,我们有很多可选的方案,具体悬着哪一种,取决于想要使用的底层缓存供应商.
我们必须选择一个缓存管理器,应用在Spring上下文中,以bean的形式对其进行配置,对于Redis,Spring data 为我们提供了 RedsiCacheManager,接下来让我们看一下如何配置吧.
Spring Data Redis 提供了一个RedisCachemanager ,这是manager的一个实现.RedsiCacheManager 会与一个Redis服务器协作,并通过RedisTemplate将缓存条目存储到Redia中.
为了使用 RedisCachemanager,我们需要Template的bean以及RedisConnectionFaction的实现类(如JedisConnectionFactory)的一个bean,
@Configuration
@EnableCaching
public class CacheConfig {
//缓存管理器
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
// Number of seconds before expiration. Defaults to unlimited (0)
cacheManager.setDefaultExpiration(3000); // Sets the default expire time (in seconds)
return cacheManager;
}
//连接工厂
@Bean
public RedisConnectionFactory redisCF(){
JedisConnectionFactory cf = new JedisConnectionFactory();
cf.setHostName("192.168.80.155");
cf.setPort(6379);
return cf;
}
//RedisTemplate
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory cf){
RedisTemplate template = new RedisTemplate();
//key会被转换为String类型,非String类型会报错
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//设置序列化为 json的对象类型,必须实现 serializable接口
Jackson2JsonRedisSerializer
可以看到,我们构建了一个RedisCacheManager,这是通过传递一个 RedisTemplate 的示例作为其构造器的参数实现的.
注意:上面的配置,在序列化非String的key时,会报错,我们可以自定义key的生成策略,首先我们需要继承 CachingConfigurerSupport,完整配置如下:
package cn.yearcon.shop.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* redis
*
* @author itguang
* @create 2017-10-31 8:26
**/
@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
/**
* 自定义key.
* 此方法将会根据类名+方法名+所有参数的值生成唯一的一个key,即使@Cacheable中的value属性一样,key也会不一样。
*/
@Override
public KeyGenerator keyGenerator() {
System.out.println("RedisCacheConfig.keyGenerator()");
return new KeyGenerator() {
@Override
public Object generate(Object o, Method method, Object... objects) {
// This will generate a unique key of the class name, the method name
//and all method parameters appended.
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName());
sb.append(method.getName());
for (Object obj : objects) {
sb.append(obj.toString());
}
System.out.println("keyGenerator=" + sb.toString());
return sb.toString();
}
};
}
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
//设置缓存过期时间 60秒*30
redisCacheManager.setDefaultExpiration(60*30);
//设置value的过期时间
Map map=new HashMap();
map.put("category",10*60L);//10分钟
map.put("product",10*60L);//10分钟
redisCacheManager.setExpires(map);
return redisCacheManager;
}
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
//定义key序列化方式
RedisSerializer redisSerializer = new StringRedisSerializer();//Long类型会出现异常信息;需要我们上面的自定义key生成策略,一般没必要
//定义value的序列化方式
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
//给 redisTemplate 设置 key 和value的生成策略
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
Spring的缓存抽象在很大程度上是围绕切面构建的,在Spring启用缓存时会创建一个切面,它会触发一个或更多的缓存注解,所有的注解都能运用在类或方法上,当其运用在单个方法上时,注解所描述的缓存只会运用到这个方法上,如果注解放在类级别上的话,那么缓存就会应用到这个类的所有方法上
Spring提供了四个注解来声明缓存规则
* @Cacheable 表明Spring在调用方法前,应该首先在缓存中查找方法的返回值,如果这个值能够找到,就返回缓存的值,否则的话买这个方法就会被调用,返回值放到缓存之中
* @CacheEvict 表明Spring应该在缓存中清除一个或者多个条目
* @CachePut 表明Spring应该将方法的返回值放到缓存中,方法的调用并不会检查缓存,方法始终都会被调用
* @Caching 这是一个分组的注解,能够同时应用多个其他的缓存注解
具体注解的API参考其它资料