SpringBoot使用Redis

欢迎光临我的博客[http://poetize.cn],前端使用Vue2,聊天室使用Vue3,后台使用Spring Boot

1.添加Redis依赖

<!-- spring boot redis 缓存引入 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.添加配置文件

# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0

3.使用

@Autowired
private StringRedisTemplate<Object,Object> stringRedisTemplate;
//StringRedisTemplate的构造器中,设置的序列化器是字符串,所以它只能存取字符串
stringRedisTemplate.opsForValue().set("aaa", "111");

4.存储对象

将POJO类实现Serializable接口即可

//redisTemplate 序列化使用的jdkSerializeable, 存储二进制字节码(可以自定义序列化)
//使用Jackson2JsonRedisSerialize 替换默认序列化
redisTemplate.opsForValue().set("user", user);
User user1 = (User) redisTemplate.opsForValue().get("user");

5.配置连接池(application.yml配置文件)

SpringBoot2.0默认采用Lettuce客户端来连接Redis服务端的。
默认是不使用连接池的,配置文件中添加lettuce.pool相关配置,则会使用到lettuce连接池,并将相关配置设置为连接池相关参数。

Lettuce 和 Jedis 的都是连接Redis Server的客户端程序。Jedis在实现上是直连redis server,多线程环境下非线程安全,除非使用连接池,为每个Jedis实例增加物理连接。Lettuce基于Netty的连接实例(StatefulRedisConnection),可以在多个线程间并发访问,且线程安全,满足多线程环境下的并发访问

SpringBoot会自动配置redis,注入相关bean

spring:
  redis:
    host: localhost    #    reids的连接ip
    database: 0    # Redis默认情况下有16个分片,这里配置具体使用的分片,默认是0
    timeout: 10000ms    # 连接超时时间(毫秒)
    lettuce:    #  springboot2.0后默认使用lettuce连接redis,底层使用的是netty框架做支撑
      pool:    
        min-idle: 0    # 连接池中的最小空闲连接 默认 0
        max-wait: -1ms    # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
        max-active: 8    # 连接池最大连接数(使用负值表示没有限制) 默认 8
        max-idle: 8    # 连接池中的最大空闲连接 默认 8

6.编写缓存配置类CacheConfig用于调优缓存默认配置

默认提供的Redis集成使用起来会有几个问题:

  • 生成Key过于简单,容易出现冲突。
  • 无法设置过期时间,乃至无法个性化每个业务单独的过期时间。
  • 默认配置序列化采用JDK序列化,某些业务场景无法满足。
    考虑以上几个问题,我们通常在集成使用Redis时,会自定义一些配置,这里我们来看看如何做自定义配置。
@Configuration
@EnableCaching  //开启缓存支持
public class RedisConfig extends CachingConfigurerSupport {

    /**
     * 重写key生成策略,缓存的key是包名+方法名+参数列表,这样就很难会冲突了
     */
    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return (target, method, objects) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append("::" + method.getName() + ":");
            for (Object obj : objects) {
                sb.append(obj.toString());
            }
            return sb.toString();
        };
    }

    /**
     * 缓存配置管理器
     */
    @Bean
    public CacheManager cacheManager(LettuceConnectionFactory lettuceConnectionFactory) {
        //以锁写入的方式创建RedisCacheWriter对象
        RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(lettuceConnectionFactory);
        //创建默认缓存配置对象
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        //设置默认过期时间是30秒
        config.entryTtl(Duration.ofSeconds(30));
        //自定义cacheConfig
        Map<String, RedisCacheConfiguration> initialCacheConfigurations = new HashMap<>();
        for (Map.Entry<String, Integer> entry : CacheExpiresMap.get().entrySet()) {
            String key = entry.getKey();
            Integer seconds = entry.getValue();
            LOGGER.info("key{},value{}", key, seconds);
            RedisCacheConfiguration initialCacheConfig = RedisCacheConfiguration.defaultCacheConfig();
            initialCacheConfigurations.put(key, initialCacheConfig.entryTtl(Duration.ofSeconds(seconds)));
        }
        //初始化RedisCacheManager
        RedisCacheManager cacheManager = new RedisCacheManager(writer, config,initialCacheConfigurations);
        return cacheManager;
    }

    /**
     * RedisTemplate配置
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
        // 设置序列化
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =
                new Jackson2JsonRedisSerializer<Object>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, Visibility.ANY);
        om.enableDefaultTyping(DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        // 配置redisTemplate
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        RedisSerializer stringSerializer = new StringRedisSerializer();

        redisTemplate.setKeySerializer(stringSerializer);   // key序列化
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);  // value序列化
        redisTemplate.setHashKeySerializer(stringSerializer);   // Hash key序列化
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);  // Hash value序列化
        //redisTemplate.setEnableTransactionSupport(true);    //是否启用事务
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Override
    @Bean
    public CacheErrorHandler errorHandler() {
        // 异常处理,当Redis发生异常时,打印日志,但是程序正常走
        LOGGER.info("初始化 -> [{}]", "Redis CacheErrorHandler");
        CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
            @Override
            public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
                LOGGER.error("Redis occur handleCacheGetError:key -> [{}]", key, e);
            }

            @Override
            public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
                LOGGER.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e);
            }

            @Override
            public void handleCacheEvictError(RuntimeException e, Cache cache, Object key)    {
                LOGGER.error("Redis occur handleCacheEvictError:key -> [{}]", key, e);
            }

            @Override
            public void handleCacheClearError(RuntimeException e, Cache cache) {
                LOGGER.error("Redis occur handleCacheClearError:", e);
            }
        };
        return cacheErrorHandler;
    }
}
posted @ 2019-08-07 17:21  LittleDonkey  阅读(1310)  评论(0编辑  收藏  举报