栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【项目demo06】SpringBoot整合Redis

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【项目demo06】SpringBoot整合Redis

我准备开一个系列,就是写一些在简要的学习项目中可能会用到的奇奇怪怪的功能,比如线程池或者统一异常处理类
取名为【项目demo】系列
然后将会同步到GitHub中:https://github.com/Livorth/FunctionalLearning


SpringBoot整合Redis

Redis是目前使用最多的非关系型数据库,如果要详细学的话,都可以开一个新系列了

我的这篇博客构建的基础是在你大致掌握了Redis之上来写的

虽然是这么说,我自己其实对redis的了解也不是很深刻,所以暂时仅了解如何使用

我的主要参考来源:

  • springboot集成redis(基础篇)

  • SpringBoot集成Redis

  • SpringBoot整合Redis及Redis工具类撰写


添加依赖与yaml配置

不管怎么样使用什么新的东西总还是要添加配置与对应配置,然后再是自定义配置与使用

  1. 添加依赖

    
        org.springframework.boot
        spring-boot-starter-data-redis
    
    
    
        org.apache.commons
        commons-pool2
    
    

    如果你不需要连接池,那么不用加上lettuce

  2. 修改对应的yaml配置

      redis:
        # 地址
        host: localhost
        # 端口号
        port: 6379
        # 密码
        password: ***
        # 超时时间,单位毫秒
        timeout: 3000
        # 数据库编号
        database: 0
        # 配置lettuce
        lettuce:
          pool:
            # 连接池中的最小空闲连接
            min-idle: 1
            # 连接池中的最大空闲连接
            max-idle: 6
            # 连接池最大连接数(使用负值表示没有限制,不要配置过大,否则可能会影响redis的性能)
            max-active: 10
            # 连接池最大阻塞等待时间(使用负值表示没有限制);单位毫秒
            max-wait: 1000
          #关闭超时时间;单位毫秒
          shutdown-timeout: 200
    

    不过实际上要说的话,其实只需要host、port、password 就可以开始使用了,其他的配置只是列出来,要配的时候知道有就好了

使用已有的RedisTemplate

springboot的redis自动装配类已经配置了一个StringRedisTemplate的bean

但是上述bean有限制条件,那就是key与value都是String,不过也可以直接使用RedisTemplate,那就是 => ,更不方便使用

public class RedisTemplate extends RedisAccessor implements RedisOperations, BeanClassLoaderAware {}

public class StringRedisTemplate extends RedisTemplate{}

当需要拓展功能的话就只能自己写RedisTemplate了,这个在后续会提及

这里仅简单测试一下其是否能正常连接redis,以及一般 => 的使用

package cn.livorth.functionallearning;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

@SpringBootTest
class FunctionalLearningApplicationTests {

    @Autowired
    private StringRedisTemplate strRedis;

    @Test
    void redisTestStringSet(){
        strRedis.opsForValue().set("RedisTest", "Test");
        strRedis.opsForValue().set("RedisTest中文", "中文测试");
    }

    @Test
    void redisTestStringGet(){
        String redisTest = strRedis.opsForValue().get("RedisTest");
        System.out.println(redisTest);
    }
}

像这种key与value都是String的使用情况,其实可以不用再自己重写RedisTemplate,作为简单的使用还是不错的选择

自定义配置RedisTemplate

在我参考的博客中,主要有两种不同复杂度的配置方案

  1. 方案一:更普遍,更简单

    这里参考博客:https://zhuanlan.zhihu.com/p/139528556

    @Configuration
    public class RedisConfig {
        @Bean
        public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) {
            // 创建redisTemplate
            RedisTemplate redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(connectionFactory);
            // 使用Jackson2JsonRedisSerialize替换默认序列化
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    
            jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
    
            // key采用String的序列化方式
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            // value序列化方式采用jackson
            redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
            // hash的key也采用String的序列化方式
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            // hash的value序列化方式采用jackson
            redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
            redisTemplate.afterPropertiesSet();
            return redisTemplate;
        }
    
  2. 方案二:结合连接池,为后续的redis集群做准备,相对复杂

    这里参考博客:https://www.cnblogs.com/vchar/p/14591566.html

    package cn.livorth.functionallearning.config;
    
    import com.fasterxml.jackson.annotation.JsonAutoDetect;
    import com.fasterxml.jackson.annotation.PropertyAccessor;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.SerializationFeature;
    import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypevalidator;
    import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
    import org.springframework.cache.CacheManager;
    import org.springframework.cache.annotation.CachingConfigurerSupport;
    import org.springframework.cache.interceptor.KeyGenerator;
    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.cache.RedisCacheWriter;
    import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
    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 org.springframework.util.DigestUtils;
    
    import java.time.Duration;
    
    
    @Configuration
    public class RedisConfig extends CachingConfigurerSupport {
    
        
        @Bean
        @Override
        public KeyGenerator keyGenerator() {
            return (target, method, params) -> {
                StringBuilder prefix = new StringBuilder();
                prefix.append(target.getClass().getName());
                prefix.append(".").append(method.getName());
                StringBuilder sb = new StringBuilder();
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return prefix.append(DigestUtils.md5DigestAsHex(sb.toString().getBytes()));
            };
        }
    
        
        @Bean
        public CacheManager cacheManager(LettuceConnectionFactory factory) {
            // 以锁写入的方式创建RedisCacheWriter对象
            RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(factory);
            // 设置缓存注解的缓存时间,缓存1小时
            Duration duration = Duration.ofSeconds(3600L);
            RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(duration);
            return new RedisCacheManager(writer, redisCacheConfiguration);
        }
    
        
        @Bean(name = "redisTemplate")
        public RedisTemplate redisTemplate(LettuceConnectionFactory factory) {
            //创建RedisTemplate对象
            RedisTemplate template = new RedisTemplate();
            template.setConnectionFactory(factory);
            //设置key的序列化方式
            template.setKeySerializer(keySerializer());
            template.setHashKeySerializer(keySerializer());
    
            //设置RedisTemplate的Value序列化方式Jackson2JsonRedisSerializer;默认是JdkSerializationRedisSerializer
            template.setValueSerializer(valueSerializer());
            template.setHashValueSerializer(valueSerializer());
    
            template.afterPropertiesSet();
            return template;
        }
    
        
        private RedisSerializer keySerializer() {
            return new StringRedisSerializer();
        }
    
        
        private RedisSerializer valueSerializer() {
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    
            ObjectMapper om = new ObjectMapper();
            // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会抛出异常
            om.activateDefaultTyping(LaissezFaireSubTypevalidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
            //解决时间序列化问题
            om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
            om.registerModule(new JavaTimeModule());
    
            jackson2JsonRedisSerializer.setObjectMapper(om);
            return jackson2JsonRedisSerializer;
        }
    
    }
      
    

    其实这两种方案实际上的配置是一样的,区别在于使用的 ConnectionFactory 不同,这里不做深入讨论,建议自行百度了解

    做这一步的配置主要原因是修改redisTemplate的序列化方式,redisTemplate原本的序列方式是JdkSerializationRedisSerializer,这里我们修改为Jackson2JsonRedisSerializer,也就是可以将传入的对象格式化为JSON。

    简单测试

    写两个接口操作redis

    UserController.java

    @GetMapping("setInCache/{id}")
    public Boolean setAllUserInCacheById(@PathVariable("id") int id){
        return userService.setAllUserInCacheById(id);
    }
    
    @GetMapping("getInCache/{id}")
    public User getAllUserInCacheById(@PathVariable("id") int id){
        return userService.getAllUserByCacheById(id);
    }
    

    UserServiceImpl.java

    @Override
    public Boolean setAllUserInCacheById(int id) {
        User user = userMapper.selectById(id);
        redisTemplate.opsForValue().set("UserInfo:" + id, user);
        return true;
    }
    
    @Override
    public User getAllUserByCacheById(int id) {
        User user = (User) redisTemplate.opsForValue().get("UserInfo:" + id);
        return user;
    }
    

    然后分别访问

    • http://localhost:8888/user/setInCache/1
    • http://localhost:8888/user/getInCache/1



    上传和获取都很成功

    封装工具类

    这里我采用的java redisUtils工具类很全中封装的工具类,太长了就不在复制粘贴了

    不过这种工具类得按照自己的需求来,很多东西得自己改或者自己写,随机应变吧

    当你的项目使用redis操作较多而且比较复杂的时候确实可以封装个工具类,但是只是随便搞点String-String缓存我觉得甚至都没必要自定义配置RedisTemplate


    写在后面

    最开始我以为Redis的整合很简单,但是当真正了解之后才知道自己目前知道的东西只是冰山一角,但是受篇幅限制这里只能简单介绍如何在SpringBoot中使用Redis,实际上还有很多内容可以单独拎出来说,比如

    • Redis集群连接配置以及读写分离:https://www.cnblogs.com/vchar/p/14591566.html

    • 高并发下穿透问题处理:https://www.cnblogs.com/shenlailai/p/10583869.html

    • 数据库同步

    还是以后时间足够再深入了解吧


    我的项目demo系列都会同步到GitHub上,欢迎围观

    https://github.com/Livorth/FunctionalLearning

    转载请注明:文章转载自 www.mshxw.com
    我们一直用心在做
    关于我们 文章归档 网站地图 联系我们

    版权所有 (c)2021-2022 MSHXW.COM

    ICP备案号:晋ICP备2021003244-6号