zoukankan      html  css  js  c++  java
  • SpringBoot2.X整合Redis

    SpringBoot2.X整合Redis

    ​ 这篇笔记主要整理SpringBoot中对Redis的整合,包括缓存的配置,以及序列化的配置,这里SpringBoot的版本为2.1.6.RELEASE

    pom文件中需要添加如下依赖

    <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!-- Spring Data Redis的启动器 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
            </dependency>
    
            <!--Lettuce pool 缓存连接池-->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-pool2</artifactId>
            </dependency>
    

    application.yml

    spring:
      redis:
        port: 6379
        host: 127.0.0.1
        database: 0
        password:
        lettuce:
          pool:
            #最大连接数
            max-active: 8
            #最大阻塞等待时间(负数表示没限制)
            max-wait: -1
            #最大空闲
            max-idle: 8
            #最小空闲
            min-idle: 0
          #连接超时时间
          timeout: 10000
    

    JedisLettuce的区别在哪?

    1、Jedis 是直连模式,在多个线程间共享一个 Jedis 实例时是线程不安全的,每个线程都去拿自己的 Jedis 实例,当连接数量增多时,物理连接成本就较高了。

    2、Lettuce的连接是基于Netty的,连接实例可以在多个线程间共享,如果你不知道Netty也没事,大致意思就是一个多线程的应用可以使用同一个连接实例,而不用担心并发线程的数量。通过异步的方式可以让我们更好地利用系统资源。

    自定义Redis配置类

    package com.ysh.config;
    
    import com.fasterxml.jackson.annotation.JsonAutoDetect;
    import com.fasterxml.jackson.annotation.PropertyAccessor;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    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.cache.interceptor.SimpleKeyGenerator;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.cache.RedisCacheConfiguration;
    import org.springframework.data.redis.cache.RedisCacheManager;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
    import org.springframework.data.redis.core.RedisOperations;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.data.redis.serializer.*;
    
    
    
    import java.nio.charset.Charset;
    
    
    import java.lang.reflect.Method;
    import java.time.Duration;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Map;
    import java.util.Set;
    
    
    /**
     * 
     * @description: redis 缓存配置类
     * @author: Ysh
     * @create: 2021-03-04
     **/
    @Configuration
    @EnableCaching
    public class RedisConfig extends CachingConfigurerSupport {
    
    
    
        /**
         * json序列化
         * @return
         */
        @Bean
        public RedisSerializer<Object> jackson2JsonRedisSerializer() {
            //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
            Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
    
            ObjectMapper mapper = new ObjectMapper();
            mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            serializer.setObjectMapper(mapper);
            return serializer;
        }
    
        @Bean
        public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
            //StringRedisTemplate的构造方法中默认设置了stringSerializer
            RedisTemplate<String, Object> template = new RedisTemplate<>();
            //set key serializer
            StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
            template.setKeySerializer(stringRedisSerializer);
            template.setHashKeySerializer(stringRedisSerializer);
    
    
            //set value serializer
            template.setDefaultSerializer(jackson2JsonRedisSerializer());
    
            template.setConnectionFactory(lettuceConnectionFactory);
            template.afterPropertiesSet();
            return template;
        }
    
        @Bean
        public StringRedisTemplate stringRedisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
            StringRedisTemplate template = new StringRedisTemplate();
            template.setConnectionFactory(lettuceConnectionFactory);
            return template;
        }
        /**
         * 在使用@Cacheable时,如果不指定key,则使用找个默认的key生成器生成的key
         *
         */
        @Override
        @Bean
        public KeyGenerator keyGenerator() {
            return new SimpleKeyGenerator() {
    
                @Override
                public Object generate(Object target, Method method, Object... params) {
                    StringBuilder sb = new StringBuilder();
                    sb.append(target.getClass().getName());
                    sb.append(".").append(method.getName());
    
                    StringBuilder paramsSb = new StringBuilder();
                    for (Object param : params) {
                        // 如果不指定,默认生成包含到键值中
                        if (param != null) {
                            paramsSb.append(param.toString());
                        }
                    }
    
                    if (paramsSb.length() > 0) {
                        sb.append("_").append(paramsSb);
                    }
                    return sb.toString();
                }
    
            };
    
        }
    
        /**
         * 管理缓存
         *
         * @param lettuceConnectionFactory
         * @return
         */
        //缓存管理器
        @Bean
        public CacheManager cacheManager(LettuceConnectionFactory lettuceConnectionFactory) {
            // 生成一个默认配置,通过config对象即可对缓存进行自定义配置
            RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
    
            // 设置缓存的默认过期时间,也是使用Duration设置,参数单位为分钟
            config = config.entryTtl(Duration.ofMinutes(5))
                    // 设置 key为string序列化
                    .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                    // 设置value为json序列化
                    .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer() ))
                    // 不缓存空值
                    .disableCachingNullValues();
    
            // 设置一个初始化的缓存空间set集合
            Set<String> cacheNames = new HashSet<>();
            cacheNames.add("user");
    
            // 对每个缓存空间应用不同的配置
            Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
            configMap.put("user", config);
    
            // 使用自定义的缓存配置初始化一个cacheManager
            RedisCacheManager cacheManager = RedisCacheManager.builder(lettuceConnectionFactory)
                    // 一定要先调用该方法设置初始化的缓存名,再初始化相关的配置
                    .initialCacheNames(cacheNames)
                    .withInitialCacheConfigurations(configMap)
                    .build();
            return cacheManager;
        }
    }
    

    缓存注解说明

    Spring 在使用缓存注解前,需要配置缓存管理器,缓存管理器将提供一些重要的信息,如缓存类型、超时时间等。 Spring 可以支持多种缓存的使用,因此它存在多种缓存处理器,并提供了缓存处理器的接口 CacheManager 和与之相关的类。

    ​ 从图中可以看到, Spring 可以支持多种缓存管理机制,而整合 Redis,主要就是以使用类 RedisCacheManager 为主。 在 Spring Boot的 starter 机制中,允许我们通过配置文件生成缓存管理器。

    ​ 在项目的配置文件中加入如下配置

    #配置redis缓存管理器
    #缓存类型,在默认的情况下,spring会自动根据上下文检索
    spring.cache.type=redis
    spring.cache.cache-names=redisCache,hashCache
    
    #是否允许redis缓存空值
    spring.cache.redis.cache-null-values=true
    #redis的键前缀
    spring.cache.redis.key-prefix=
    #缓存超时时间戳,配置为0则不设置超时时间
    spring.cache.redis.time-to-live=6000ms
    #是否启用redis的键前缀
    spring.cache.redis.use-key-prefix=false
    

    配置参数解析

    • spring.cache.type
      spring.cache.type 配置的是缓存类型,这里配置为 Redis, Spring Boot 就会自动生成 RedisCacheManager 对象。
    • spring.cache.cache-names
      spring.cache.cache-names 配置的是缓存名称,多个名称可以使用逗号分隔,以便于缓存注解的引用。

    当然,我们已经在上面的配置类中配置好了相关的缓存配置,所以不用在application.yml中进行配置,系统会自动覆盖默认的配置。

    最后为了使用缓存管理器,需要在 Spring Boot 的配置文件中加入驱动缓存的注解@EnableCaching,这样就可以驱动 Spring 缓存机制工作了。

    常用的缓存注解

    @Cacheable

    使用了此注解的方法会将返回值放到缓存数据库中

    参数解析

    • value
      存到缓存中的空间名字,如果同一个模块,建议这个模块下的value值是同一个

    • key
      给存储的值起个名称,在查询时如果缓存中有名称相同的,那么则直接从缓存中将数据返回。命名规则一般是:"固定值" 或 key = "#sellerid"(可变化的值) ,如果该方法没有参数,key要省略,会自动生成key,前提是配置了key的生成策略

    • condition

      里面填写表达式,true表示进行缓存,false表示不进行缓存,表达式格式一般为:"#sellerid.length > 10"

    @CacheEvict

    表示通过定义的键移除缓存,一般定义在增删改方法上

    参数解析

    • value

      同上

    • key

      同上

    • allEntries

      allEntries = false 清空对应的value空间里面的所有值,allEntries = true 默认值,删除key对应的值,建议改为false,因为实际业务中,会有查询全部的操作,也会有根据ID查询的,如果删除了某一条信息,那么要删除哪个key对应的值呢?所以还是改为false,全部删除,等查询的时候,再存最新的。

    @CachePut

    每次执行都会执行方法,无论缓存里是否有值,同时使用新的返回值的替换缓存中的值。这里不同于@Cacheable:@Cacheable如果缓存没有值,从则执行方法并缓存数据,如果缓存有值,则从缓存中获取值

    @CacheConfig

    @CacheConfig: 类级别的注解:如果我们在此注解中定义value,则此类中的所有方法上 @Cacheablevalue默认都是此值。当然@Cacheable也可以重定义value的值

    使用lettuce连接池搭建Redis集群

    spring:
      redis:
        timeout: 6000ms # 连接超时时长(毫秒)
        password: 
        cluster:
          max-redirects: 3  # 获取失败 最大重定向次数 
          nodes:
            - 127.0.0.1:6380
            - 127.0.0.1.236:6381
            - 127.0.0.1.236:6382
            - 127.0.0.1.244:6383
            - 127.0.0.1.244:6384
            - 127.0.0.1.244:6385 
        lettuce:
          pool:
            max-active: 1000  #连接池最大连接数(使用负值表示没有限制)
            max-idle: 10 # 连接池中的最大空闲连接
            min-idle: 5 # 连接池中的最小空闲连接
            max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
    
    我等的船还不来
  • 相关阅读:
    圖標網址
    webmethod Ajax请求格式和返回类型 汇总
    第一阶段图标动效打卡
    大数据可视化--控件设计
    Python 多任务(进程) day1(3)
    Python 多任务(进程) day1(2)
    Python 多任务(进程) day1(1)
    Python 多任务(线程) day2 (2)
    Python 多任务(线程) day1
    TCP和UDP的一些注意事项
  • 原文地址:https://www.cnblogs.com/lxs1204/p/14483407.html
Copyright © 2011-2022 走看看