软件编程
位置:首页>> 软件编程>> java编程>> Spring Boot整合Redis的完整步骤

Spring Boot整合Redis的完整步骤

作者:Jian  发布时间:2023-06-03 03:21:56 

标签:springboot,整合,redis
目录
  • 前言

  • 一、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

    Spring Boot整合Redis的完整步骤 

    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控制台中:

    Spring Boot整合Redis的完整步骤 

    在登录客户端后查看value值

     Spring Boot整合Redis的完整步骤

    总结

    来源:https://www.cnblogs.com/jian0110/p/10833056.html

    0
    投稿

    猜你喜欢

    手机版 软件编程 asp之家 www.aspxhome.com