Kotlin+SpringBoot与Redis整合详解

1、Redis是简介

2、Redis开发者

  • redis 的作者,叫Salvatore Sanfilippo,来自意大利的西西里岛,现在居住在卡塔尼亚。目前供职于Pivotal公司。他使用的网名是antirez。

3、Redis安装

  • Redis安装与其他知识点请参考几年前我编写文档 Redis Detailed operating instruction.pdf,这里不做太多的描述,主要讲解在kotlin+SpringBoot然后搭建Redis与遇到的问题

Redis详细使用说明书.pdf

image.png

4、Redis应该学习那些?

  • 列举一些常见的内容


    Redis.png

5、Redis有哪些命令

Redis官方命令清单

  • Redis常用命令


    Redis常用命令.png

6、 Redis常见应用场景

应用场景.png

7、 Redis常见的几种特征

  • Redis的哨兵机制
  • Redis的原子性
  • Redis持久化有RDB与AOF方式

8、工程结构

工程结构.png

9、Kotlin与Redis的代码实现

  • Redis 依赖的Jar配置
<!-- Spring Boot Redis 依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>
  • RedisProperties代码
@Component
@Configuration
@ConfigurationProperties(prefix = "redis")
open  class RedisProperties {
    
    // Redis服务器地址
    var host: String = "192.168.1.133"
    // Redis服务器连接端口
    var port: Int = 6739
    // Redis服务器连接密码(默认为空)
    var password: String = ""
    // 连接超时时间(毫秒)
    var timeout: Int = 5000
    // 连接超时时间(毫秒)
    var database: Int = 1
    // 连接池最大连接数(使用负值表示没有限制)
    var maxTotal: Int = 8
    // 连接池最大阻塞等待时间(使用负值表示没有限制)
    var maxWaitMillis: Int = 1
    // 连接池中的最大空闲连接
    var maxIdle: Int = 8
    // 连接池中的最小空闲连接
    var minIdle: Int = 8
}
  • RedisTemplateDataSource代码
/**
 *参考博客: https://blog.csdn.net/New_CJ/article/details/84892543
 */
@Component
@EnableCaching // 启动缓存
@Configuration
@EnableConfigurationProperties(RedisProperties::class)
open class RedisTemplateDataSource : CachingConfigurerSupport  {

    
    // Redis服务器地址
    var host: String = "192.168.1.133"
    // Redis服务器连接端口
    var port: Int = 6739
    // Redis服务器连接密码(默认为空)
    var password: String = ""
    // 连接超时时间(毫秒)
    var timeout: Int = 5000
    // 连接超时时间(毫秒)
    var database: Int = 1
    // 连接池最大连接数(使用负值表示没有限制)
    var maxTotal: Int = 8
    // 连接池最大阻塞等待时间(使用负值表示没有限制)
    var maxWaitMillis: Int = 1
    // 连接池中的最大空闲连接
    var maxIdle: Int = 8
    // 连接池中的最小空闲连接
    var minIdle: Int = 8
    
    
    //解決This type has a constructor, and thus must be initialized here異常信息
    constructor()
 
    //获取配置信息构造方法
    constructor(host:String,port:Int,password: String ,timeout: Int,database: Int,maxTotal: Int ,maxWaitMillis: Int,maxIdle: Int,minIdle: Int ){
        this.host= host
        this.port = port
        this.password= password
        this.timeout= timeout
        this.database=database
        this.maxTotal=maxTotal
        this.maxWaitMillis=maxWaitMillis
        this.maxIdle=maxIdle
        this.minIdle=minIdle
    }
    
    
    companion object {
        private val log: Logger = LoggerFactory.getLogger(RedisTemplateDataSource::class.java)
    }
    
    
    @Autowired lateinit var redisProperties: RedisProperties
    
    /**
     * 配置JedisPoolConfig
     * @return JedisPoolConfig实体
     */
    @Bean(name = arrayOf("jedisPoolConfig"))
    open fun jedisPoolConfig(): JedisPoolConfig {
        log.info("初始化JedisPoolConfig");
        var jedisPoolConfig = JedisPoolConfig();
        // 连接池最大连接数(使用负值表示没有限制)
        jedisPoolConfig.setMaxTotal(redisProperties.maxTotal);
        // 连接池最大阻塞等待时间(使用负值表示没有限制)
        jedisPoolConfig.setMaxWaitMillis(redisProperties.maxWaitMillis.toLong());
        // 连接池中的最大空闲连接
        jedisPoolConfig.setMaxIdle(redisProperties.maxIdle);
        // 连接池中的最小空闲连接
        jedisPoolConfig.setMinIdle(redisProperties.minIdle);
        // jedisPoolConfig.setTestOnBorrow(true);
        // jedisPoolConfig.setTestOnCreate(true);
        // jedisPoolConfig.setTestWhileIdle(true);
        return jedisPoolConfig;
    }


    /**
     * 实例化 RedisConnectionFactory 对象
     * @param poolConfig
     * @return
     */
    @Bean(name = arrayOf("jedisConnectionFactory"))
    open fun jedisConnectionFactory(@Qualifier(value = "jedisPoolConfig") poolConfig: JedisPoolConfig): RedisConnectionFactory {
        log.info("初始化RedisConnectionFactory");
        var jedisConnectionFactory = JedisConnectionFactory(poolConfig);
        jedisConnectionFactory.hostName=redisProperties.host
        jedisConnectionFactory.port=redisProperties.port
        jedisConnectionFactory.database=redisProperties.database
        return jedisConnectionFactory;
    }

    /**
     *  实例化 RedisTemplate 对象
     * @return
     */
    @Bean(name = arrayOf("redisTemplateStr"))
    open fun redisTemplateStr(@Qualifier(value = "jedisConnectionFactory") factory: RedisConnectionFactory): RedisTemplate<String, String> {
        log.info("初始化RedisTemplate");
        var redisTemplate = RedisTemplate<String, String>();
        redisTemplate.setConnectionFactory(factory);
        redisTemplate.setKeySerializer(StringRedisSerializer());
        redisTemplate.setHashKeySerializer(StringRedisSerializer());
        redisTemplate.setHashValueSerializer(JdkSerializationRedisSerializer());
        redisTemplate.setValueSerializer(JdkSerializationRedisSerializer());
        redisTemplate.afterPropertiesSet();
        redisTemplate.setEnableTransactionSupport(true);
        return redisTemplate;
    }


    @Bean
    override
    fun cacheManager() : CacheManager{ 
        var redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5));
        return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(jedisConnectionFactory(jedisPoolConfig())))
               .cacheDefaults(redisCacheConfiguration).build();
    }
 
    
    @Bean(value = arrayOf("redisTemplate"))
    open fun redisTemplate(jedisConnectionFactory: JedisConnectionFactory): RedisTemplate<String, Any> {
        //设置序列化
        var jackson2JsonRedisSerializer = Jackson2JsonRedisSerializer(Object::class.java);
        var om = ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置redisTemplate
        var redisTemplate = RedisTemplate<String, Any>();
        redisTemplate.setConnectionFactory(jedisConnectionFactory);
        var stringSerializer = StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer); // key序列化
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // value序列化
        redisTemplate.setHashKeySerializer(stringSerializer); // Hash key序列化
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); // Hash value序列化
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}
  • RedisAutoConfiguration代码

@EnableConfigurationProperties(RedisProperties::class)
open class RedisAutoConfiguration {
    
    @Autowired lateinit var redisProperties: RedisProperties;
    
    @Bean
    @ConditionalOnMissingBean(RedisTemplateDataSource::class)
    @ConditionalOnProperty(name = arrayOf("redis.host"))
    open fun redisTemplateDataSource():RedisTemplateDataSource {
        return RedisTemplateDataSource(redisProperties.host,redisProperties.port,redisProperties.password,
            redisProperties.timeout,redisProperties.database,redisProperties.maxTotal,
            redisProperties.maxWaitMillis,redisProperties.maxIdle,redisProperties.minIdle)
    }
}
  • META-INF的spring.factories配置

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.flong.kotlin.core.redis.RedisAutoConfiguration
  • Controller代码

@Autowired lateinit var stringRedisTemplate: StringRedisTemplate

//RedisTemplateK, V>这个类由于有K与V,下面的做法是必须要指定Key-Value
//2 type arguments expected for class RedisTemplate
@Autowired lateinit var redisTemplate : RedisTemplate<String,Any>;

    //简单的缓存测试1
    @RequestMapping("/getUserByRedis/{userId}")
    fun getUserByRedis(@PathVariable("userId") userId: Long) {
        var redis_key   = USER_REDIS_KEY + "_" + userId;
        var user        = stringRedisTemplate.opsForValue().get(redis_key)
        if (user == null) {
            var userObj  = userService.getUserId(userId)
            stringRedisTemplate.opsForValue().set(redis_key, userObj.toString())
            print("从DB获取----" + JSON.toJSONString(userObj));

        } else {
            print("从缓存获取----" + JSON.toJSONString(user));
        }

    }


    //简单的缓存测试2
    @RequestMapping("/getUserByRedis1/{userId}")
    fun getUserByRedis1(@PathVariable("userId") userId: Long) {
        var redis_key   = USER_REDIS_KEY + "_" + userId;
        var user        = redisTemplate.opsForValue().get(redis_key)
        if (user == null) {
            var userObj  = userService.getUserId(userId)
            redisTemplate.opsForValue().set(redis_key, userObj.toString())
            print("从DB获取----" + JSON.toJSONString(userObj));

        } else {
            print("从缓存获取----" + JSON.toJSONString(user));
        }

    }

注意:RedisTemplateK, V>这个类由于有K与V,下面的做法是必须要指定Key-Value 2 type arguments expected for class RedisTemplate

  • 运行结果

  • 运行结果.png

10、参考文章

参考Springboot2.0 使用redis @cacheable等注解缓存博客

11、工程架构源代码

Kotlin+SpringBoot与Redis整合工程源代码

12 、总结与建议

  • 1 、以上问题根据搭建 kotlin与Redis实际情况进行总结整理,除了技术问题查很多网上资料,通过自身进行学习之后梳理与分享。

  • 2、 在学习过程中也遇到很多困难和疑点,如有问题或误点,望各位老司机多多指出或者提出建议。本人会采纳各种好建议和正确方式不断完善现况,人在成长过程中的需要优质的养料。

  • 3、 希望此文章能帮助各位老铁们更好去了解如何在 kotlin上搭建RabbitMQ,也希望您看了此文档或者通过找资料亲身经历实操学习效果会更好。

备注:此文章属于本人原创,欢迎转载和收藏.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容