Springboot整合reidis详解

来源:互联网 发布:手机壳品牌知乎 编辑:程序博客网 时间:2024/06/08 11:58

springBoot集成redis的key,value序列化的相关问题

使用redis操作key-value数据

Spring Data Redis 包含了多个模版实现,用来完成Redis数据库的数据存储功能

但是为了创建spring data redis的模版,我们首先要有一个redis的链接工厂.

1.连接到redis

redis链接工厂会生成到redis数据库服务器的链接.spring data redis为四种redis客户端提供了链接工厂.

  • JedisConnectionFactory
  • JredisConnectionFaction
  • LettuceConnectionFaction
  • SrpConnectionFaction

可自行选择链接工厂.

在做出决策后,我们就可以将连接工厂配置为 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模版了

2.使用 RedisTemplate

顾名思义,Redis连接工厂会生成到 redis key-value 的存储连接(以RedisConnection的形式).

借助connection我们就可以读取数据.

与其它的 spring data项目类似,spring data redis以模版的形式提供了较高等级的数据访问方案,实际上,有两个模版:

  • RedisTemplate
  • StringRedisTemplate
@Configurationpublic class CacheConfig {    @Bean    public RedisConnectionFactory redisCF(){        JedisConnectionFactory cf = new JedisConnectionFactory();        cf.setHostName("192.168.80.155");        cf.setPort(6379);        return cf;    }    @Bean    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf){        RedisTemplate<String,String> template = new RedisTemplate<String,String>();        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");    }}

3.使用key 和value的序列化器

当某个条目保存到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 ,这在我们意料之中.

设置key和value的序列化器

    @Bean    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf){        RedisTemplate<String,String> template = new RedisTemplate<String,String>();        //key会被转换为String类型,非String类型会报错        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();        //设置序列化为 json的对象类型,必须实现 serializable接口        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);        template.setConnectionFactory(cf);        template.setKeySerializer(stringRedisSerializer);        template.setValueSerializer(jackson2JsonRedisSerializer);        return template;    }

Spring 声明式缓存

Spring 对缓存的支持有两者方式:

  • 注解驱动的支持
  • XML声明的缓存

使用Spring的缓存抽象时,最为通用的方法就是在方法上添加 @Cacheable 注解 和 @CacheEvict 注解.

在往bean方法上添加缓存之前,必须先启用Spring对注解驱动缓存的支持.

如果我们使用java配置的话,可以在一个配置类上添加 @EnableCaching ,这样就能启用注解驱动的缓存

@Configuration@EnableCachingpublic class AnnoCacheConfig {    //声明缓存管理器    @Bean    public CacheManager cacheManager(){        CacheManager cacheManager = new ConcurrentMapCacheManager();        return cacheManager;    }}

在上例中我们还声明了一个缓存管理器的bean.缓存管理器是Spring抽象的核心,它能够与多个流行的缓存实现进行集成

在本例中声明了 ConcurrentMapCacheManager,这个简单的缓存管理器,是基于内存的,所以它的声明周期是与应用相关联的,
幸好,有多个很棒的缓存管理器方案可供使用.

在为 Spring的缓存抽象选择管理器时,我们有很多可选的方案,具体悬着哪一种,取决于想要使用的底层缓存供应商.

我们必须选择一个缓存管理器,应用在Spring上下文中,以bean的形式对其进行配置,对于Redis,Spring data 为我们提供了 RedsiCacheManager,接下来让我们看一下如何配置吧.

配置注解式 Redis缓存

Spring Data Redis 提供了一个RedisCachemanager ,这是manager的一个实现.RedsiCacheManager 会与一个Redis服务器协作,并通过RedisTemplate将缓存条目存储到Redia中.

为了使用 RedisCachemanager,我们需要Template的bean以及RedisConnectionFaction的实现类(如JedisConnectionFactory)的一个bean,

@Configuration@EnableCachingpublic 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<String, String> redisTemplate(RedisConnectionFactory cf){        RedisTemplate<String,String> template = new RedisTemplate<String,String>();        //key会被转换为String类型,非String类型会报错        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();        //设置序列化为 json的对象类型,必须实现 serializable接口        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);        template.setConnectionFactory(cf);        template.setKeySerializer(stringRedisSerializer);        template.setValueSerializer(jackson2JsonRedisSerializer);        return template;    }//  @Bean//  public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory cf){//      return new StringRedisTemplate();//  }}

可以看到,我们构建了一个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@EnableCachingpublic 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<String,Long> map=new HashMap();        map.put("category",10*60L);//10分钟        map.put("product",10*60L);//10分钟        redisCacheManager.setExpires(map);        return redisCacheManager;    }    @Bean    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();        redisTemplate.setConnectionFactory(factory);        //定义key序列化方式        RedisSerializer<String> 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参考其它资料