Springboot整合reidis详解

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
@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");



    }

}

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 redisTemplate(RedisConnectionFactory cf){

        RedisTemplate template = new RedisTemplate();
        //key会被转换为String类型,非String类型会报错
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        //设置序列化为 json的对象类型,必须实现 serializable接口
        Jackson2JsonRedisSerializer 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
@EnableCaching
public 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
@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 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
@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参考其它资料

你可能感兴趣的:(spring)