当前位置 : 主页 > 编程语言 > java >

Spring Boot整合Redis的完整步骤

来源:互联网 收集:自由互联 发布时间:2021-07-07
目录 前言 一、Spring Boot对Redis的支持 二、实战 1、添加依赖 2、redis配置 3、实现序列化 4、创建Redis连接工厂,同时注册Bean 5、完整的RedisConfig配置类 三、测试 1、编写redis工具类 2、Pe
目录
  • 前言
  • 一、Spring Boot对Redis的支持
  • 二、实战
    • 1、添加依赖
    • 2、redis配置
    • 3、实现序列化
    • 4、创建Redis连接工厂,同时注册Bean
    • 5、完整的RedisConfig配置类
  • 三、测试
    • 1、编写redis工具类
    • 2、Person实体类
    • 3、编写测试类
    • 4、测试结果
  • 总结

    前言

    实际 开发 中 缓存 处理是必须的,不可能我们每次客户端去请求一次 服务器 ,服务器每次都要去 数据库 中进行查找,为什么要使用缓存?说到底是为了提高系统的运行速度。将用户频繁访问的内容存放在离用户最近,访问速度最 快的 地方,提高用户的响 应速度,今天先来讲下在 springboot 中整合 redis 的详细步骤。

    一、Spring Boot对Redis的支持

    Spring对Redis的支持是使用Spring Data Redis来实现的,一般使用Jedis或者lettuce(默认),Java客户端在 org.springframework.boot.autoconfigure.data.redis(Spring Boot 2.x) 中redis的自动配置 AutoConfigureDataRedis

     

    RedisAutoConfiguration提供了RedisTemplate与StringRedisTemplate(只针对键值都是字符型的数据)模板,其中注解 @ConditionalOnMissingBean 是关键,表明该Bean如果在Spring中已经存在,则忽略,如果没有存在则在此处注册由Spring管理,也就是说我们可以“重写”该bean,实现自己的RedisTemplate与StringRedisTemplate,事实上,是要需要重写的,理由如下:

    • 没有实现我们所需要的序列化;
    • 泛型总是<Object, Object>,大部分场景我们更需要<String, Object>。
    @Bean
     @ConditionalOnMissingBean(
      name = {"redisTemplate"}
     )
     public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
      RedisTemplate<Object, Object> template = new RedisTemplate();
      template.setConnectionFactory(redisConnectionFactory);
      return template;
     }
    
     @Bean
     @ConditionalOnMissingBean
     public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
      StringRedisTemplate template = new StringRedisTemplate();
      template.setConnectionFactory(redisConnectionFactory);
      return template;
     }

    二、实战

    1、添加依赖

    1)需要spring-boot-starter-cache依赖,管理缓存

    <!-- Spring Boot Cache -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>

    2)需要spring-boot-starter-data-redis依赖(注:spring boot 2.x改为在data下),支持redis:主要以为Jedis客户端为主,排除默认的lettuce作为客户端的依赖

    <!-- Redis Cache -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
      <!-- 排除lettuce包,使用jedis代替-->
      <exclusions>
        <exclusion>
          <groupId>io.lettuce</groupId>
          <artifactId>lettuce-core</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

    3)需要jedis-client依赖(注:Redis Client 3版本以上会报错与spring-boot-starter-data-redis冲突,最好使用2.9.x),使用jedis作为客户端

    <!-- Redis Client 3版本以上会报错与spring-boot-starter-data-redis冲突 -->
    <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>2.9.0</version>
    </dependency>

    2、redis配置

    创建RedisConfig配置类,增加@Configuration注解,同时开启缓存管理支持(添加注解@EnableCaching),继承CachingConfigurerSupport重写key生成策略

    @Configuration
    @EnableCaching
    public class RedisConfig extends CachingConfigurerSupport {
       /**
       * 生成key的策略:根据类名+方法名+所有参数的值生成唯一的一个key
       * @return
       */
      @Bean
      @Override
      public KeyGenerator keyGenerator() {
        return (Object target, Method method, Object... params) -> {
          StringBuilder sb = new StringBuilder();
          sb.append(target.getClass().getName());
          sb.append(method.getName());
          for (Object obj : params) {
            sb.append(obj.toString());
          }
          return sb.toString();
        };
      }
    
    }

    之后使用的application.yml配置文件,其中这里已经选择jedis作为客户端。

    # redis 配置
     redis:
       port: 6379
       # Redis服务器连接密码(默认为空)
       password:
       host: xxx.xxx.xxx.xxx
       database: 0
       jedis:
        pool:
         #连接池最大连接数(使用负值表示没有限制)
         max-active: 300
         # 连接池中的最小空闲连接
         max-idle: 100
          # 连接池最大阻塞等待时间(使用负值表示没有限制)
         max-wait: 10000
         # 连接超时时间(毫秒)
         timeout: 5000

    同时读取配置属性,注入JedisPoolConfig

    /**
       * redis配置属性读取
       */
      @Value("${spring.redis.host}")
      private String host;
      @Value("${spring.redis.port}")
      private int port;
      @Value("${spring.redis.database}")
      private int database;
      @Value("${spring.redis.jedis.pool.max-idle}")
      private int maxIdle;
      @Value("${spring.redis.jedis.pool.max-wait}")
      private long maxWaitMillis;
      @Value("${spring.redis.jedis.pool.max-active}")
      private int maxActive;
    
    
      /**
       * JedisPoolConfig配置
       * @return
       */
      @Bean
      public JedisPoolConfig jedisPoolConfig() {
        log.info("初始化JedisPoolConfig");
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(maxActive);
        jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
        jedisPoolConfig.setMaxIdle(maxIdle);
        return jedisPoolConfig;
      }

    3、实现序列化

    针对RedisTemplate或StringRedisTemplate进行序列化,同时重写注册Bean

    RedisTemplate默认使用JdkSerializationRedisSerializer,StringRedisTmeplate默认使用的是StringRedisSerializer。但都是不符合实际要求的

    /**
       * 重新实现RedisTemplate:解决序列化问题
       * @param redisConnectionFactory
       * @return
       */
      @Bean
      @SuppressWarnings({"rawtype", "unchecked"})
      public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<String, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        // 设置任何字段可见
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 设置不是final的属性可以转换
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        log.info("objectMapper: {}", om);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson序列化方式
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson序列化方式
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        template.setEnableTransactionSupport(true);
        return template;
      }
    
      /**
       * 重新实现StringRedisTmeplate:键值都是String的的数据
       * @param redisConnectionFactory
       * @return
       */
      @Bean
      public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        template.setConnectionFactory(redisConnectionFactory);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson序列化方式
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson序列化方式
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        return template;
      }

    4、创建Redis连接工厂,同时注册Bean

    注意Spring Boot 1.x与Spring Boot 2.x的区别,已在代码中注释表明,Spring Boot 1.x使用的是JedisConnectionFactory 。而Spring Boot 2.x使用的是RedisStandaloneConfiguration ,之后传入JedisConnectionFactory返回Bean

    /**
       * 注入RedisConnectionFactory
       * @return
       */
      @Bean
      public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
        log.info("初始化JedisConnectionFactory");
        /* 在Spring Boot 1.x中已经过时,采用RedisStandaloneConfiguration配置
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);
        jedisConnectionFactory.setHostName(host);
        jedisConnectionFactory.setDatabase(database);*/
    
        // JedisConnectionFactory配置hsot、database、password等参数
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(port);
        redisStandaloneConfiguration.setDatabase(database);
        // JedisConnectionFactory配置jedisPoolConfig
        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jedisPoolConfigBuilder =
            (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();
        jedisPoolConfigBuilder.poolConfig(jedisPoolConfig);
        return new JedisConnectionFactory(redisStandaloneConfiguration);
    
      }

    5、完整的RedisConfig配置类

    /**
     *
     * @author jian
     * @date 2019/4/14
     * @description
     * 1) RedisTemplate(或StringRedisTemplate)虽然已经自动配置,但是不灵活(第一没有序列化,第二泛型为<Object, Object>不是我们想要的类型)
     * 所以自己实现RedisTemplate或StringRedisTemplate)
     * 2) 采用RedisCacheManager作为缓存管理器
     *
     */
    
    @Configuration
    @EnableCaching
    public class RedisConfig extends CachingConfigurerSupport {
    
      private static final Logger log = LoggerFactory.getLogger(RedisConfig.class);
    
      /**
       * redis配置属性读取
       */
      @Value("${spring.redis.host}")
      private String host;
      @Value("${spring.redis.port}")
      private int port;
      @Value("${spring.redis.database}")
      private int database;
      @Value("${spring.redis.jedis.pool.max-idle}")
      private int maxIdle;
      @Value("${spring.redis.jedis.pool.max-wait}")
      private long maxWaitMillis;
      @Value("${spring.redis.jedis.pool.max-active}")
      private int maxActive;
    
    
      /**
       * JedisPoolConfig配置
       * @return
       */
      @Bean
      public JedisPoolConfig jedisPoolConfig() {
        log.info("初始化JedisPoolConfig");
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(maxActive);
        jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
        jedisPoolConfig.setMaxIdle(maxIdle);
        return jedisPoolConfig;
      }
    
      /**
       * 注入RedisConnectionFactory
       * @return
       */
      @Bean
      public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
        log.info("初始化JedisConnectionFactory");
        /* 在Spring Boot 1.x中已经过时,采用RedisStandaloneConfiguration配置
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);
        jedisConnectionFactory.setHostName(host);
        jedisConnectionFactory.setDatabase(database);*/
    
        // JedisConnectionFactory配置hsot、database、password等参数
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(port);
        redisStandaloneConfiguration.setDatabase(database);
        // JedisConnectionFactory配置jedisPoolConfig
        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jedisPoolConfigBuilder =
            (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();
        jedisPoolConfigBuilder.poolConfig(jedisPoolConfig);
        return new JedisConnectionFactory(redisStandaloneConfiguration);
    
      }
    
      /**
       * 采用RedisCacheManager作为缓存管理器
       * @param connectionFactory
       */
      @Bean
      public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheManager redisCacheManager = RedisCacheManager.create(connectionFactory);
        return redisCacheManager;
      }
    
    
      /**
       * 生成key的策略:根据类名+方法名+所有参数的值生成唯一的一个key
       * @return
       */
      @Bean
      @Override
      public KeyGenerator keyGenerator() {
        return (Object target, Method method, Object... params) -> {
          StringBuilder sb = new StringBuilder();
          sb.append(target.getClass().getName());
          sb.append(method.getName());
          for (Object obj : params) {
            sb.append(obj.toString());
          }
          return sb.toString();
        };
      }
    
      /**
       * 重新实现RedisTemplate:解决序列化问题
       * @param redisConnectionFactory
       * @return
       */
      @Bean
      @SuppressWarnings({"rawtype", "unchecked"})
      public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<String, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        // 设置任何字段可见
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 设置不是final的属性可以转换
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        log.info("objectMapper: {}", om);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson序列化方式
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson序列化方式
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        template.setEnableTransactionSupport(true);
        return template;
      }
    
      /**
       * 重新实现StringRedisTmeplate:键值都是String的的数据
       * @param redisConnectionFactory
       * @return
       */
      @Bean
      public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        template.setConnectionFactory(redisConnectionFactory);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson序列化方式
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson序列化方式
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        return template;
      }
    
    }

    三、测试

    1、编写redis工具类

    虽然RedisTemplate与StringRedisTemplate模板有提供的主要数据访问方法:

    • opsForValue():操作只有简单属性的数据
    • opsForList():操作含有List的数据
    • opsForSet():操作含有set的数据
    • opsForHash():操作含有hash的数据
    • opsForZSet():操作含有有序set类型ZSet的数据

    但是相关比较抽象,实现起来比较复杂,有必要进一步封装,比如使用redisTmeplate中的简单value的get操作:

    Object result = null;
    ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
    result = operations.get(key);

    但是封装之后,相对客户端用户来说比较明了

    /**
       * 读取缓存
       *
       * @param key
       * @return
       */
      public Object get(final String key) {
        Object result = null;
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        return result;
      }

    完整的简单工具类如下:

    @Component
    public class RedisUtils {
    
    
      @Autowired
      private RedisTemplate redisTemplate;
    
      /**
       * 批量删除对应的value
       *
       * @param keys
       */
      public void remove(final String... keys) {
        for (String key : keys) {
          remove(key);
        }
      }
    
      /**
       * 批量删除key
       *
       * @param pattern
       */
      public void removePattern(final String pattern) {
        Set<Serializable> keys = redisTemplate.keys(pattern);
        if (keys.size() > 0) {
          redisTemplate.delete(keys);
        }
      }
    
      /**
       * 删除对应的value
       *
       * @param key
       */
      public void remove(final String key) {
        if (exists(key)) {
          redisTemplate.delete(key);
        }
      }
    
      /**
       * 判断缓存中是否有对应的value
       *
       * @param key
       * @return
       */
      public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
      }
    
      /**
       * 读取缓存
       *
       * @param key
       * @return
       */
      public Object get(final String key) {
        Object result = null;
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        return result;
      }
    
      /**
       * 写入缓存
       *
       * @param key
       * @param value
       * @return
       */
      public boolean set(final String key, Object value) {
        boolean result = false;
        try {
          ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
          operations.set(key, value);
          result = true;
        } catch (Exception e) {
          e.printStackTrace();
        }
        return result;
      }
    
      /**
       * 写入缓存
       *
       * @param key
       * @param value
       * @return
       */
      public boolean set(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
          ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
          operations.set(key, value);
          redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
          result = true;
        } catch (Exception e) {
          e.printStackTrace();
        }
        return result;
      }
    }

    2、Person实体类

    需要注意的是一定要实现序列化,并且有序列化版本ID

    public class Person implements Serializable {
      private final long serialVersionUID = 1L;
    
      private String id;
      private String name;
      private int age;
      private String gender;
    
      public String getId() {
        return id;
      }
    
      public void setId(String id) {
        this.id = id;
      }
    
      public String getName() {
        return name;
      }
    
      public void setName(String name) {
        this.name = name;
      }
    
      public int getAge() {
        return age;
      }
    
      public void setAge(int age) {
        this.age = age;
      }
    
      public String getGender() {
        return gender;
      }
    
      public void setGender(String gender) {
        this.gender = gender;
      }
    
      @Override
      public String toString() {
        return "Person{" +
            "id='" + id + '\'' +
            ", name='" + name + '\'' +
            ", age=" + age +
            ", gender='" + gender + '\'' +
            '}';
      }
    }

    3、编写测试类

    Redis工具类Spring已经做了管理(增加@Compent注解),使用很简单,只需要注入RedisUtils即可

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class RedisTest {
    
      @Autowired
      private RedisUtils redisUtils;
    
      @Test
      public void test(){
        Person person = new Person();
        person.setAge(23);
        person.setId("001");
        person.setName("Zhangsan");
        redisUtils.set("person-001", person);
        System.out.println(redisUtils.get("person-001"));
      }
    
    }

    4、测试结果

    在IDE控制台中:

     

    在登录客户端后查看value值

     

    总结

    以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对自由互联的支持。

    网友评论