Kotlin+SpringBoot與Redis整合詳解

1、Redis是簡介

2争便、Redis開發(fā)者

  • redis 的作者级零,叫Salvatore Sanfilippo,來自意大利的西西里島滞乙,現(xiàn)在居住在卡塔尼亞奏纪。目前供職于Pivotal公司。他使用的網(wǎng)名是antirez斩启。

3序调、Redis安裝

  • Redis安裝與其他知識點請參考幾年前我編寫文檔 Redis Detailed operating instruction.pdf,這里不做太多的描述兔簇,主要講解在kotlin+SpringBoot然后搭建Redis與遇到的問題

Redis詳細使用說明書.pdf

image.png

4发绢、Redis應(yīng)該學(xué)習(xí)那些硬耍?

  • 列舉一些常見的內(nèi)容


    Redis.png

5、Redis有哪些命令

Redis官方命令清單

  • Redis常用命令


    Redis常用命令.png

6边酒、 Redis常見應(yīng)用場景

應(yīng)用場景.png

7经柴、 Redis常見的幾種特征

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

8、工程結(jié)構(gòu)

工程結(jié)構(gòu).png

9墩朦、Kotlin與Redis的代碼實現(xiàn)

  • 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服務(wù)器地址
    var host: String = "192.168.1.133"
    // Redis服務(wù)器連接端口
    var port: Int = 6739
    // Redis服務(wù)器連接密碼(默認為空)
    var password: String = ""
    // 連接超時時間(毫秒)
    var timeout: Int = 5000
    // 連接超時時間(毫秒)
    var database: Int = 1
    // 連接池最大連接數(shù)(使用負值表示沒有限制)
    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服務(wù)器地址
    var host: String = "192.168.1.133"
    // Redis服務(wù)器連接端口
    var port: Int = 6739
    // Redis服務(wù)器連接密碼(默認為空)
    var password: String = ""
    // 連接超時時間(毫秒)
    var timeout: Int = 5000
    // 連接超時時間(毫秒)
    var database: Int = 1
    // 連接池最大連接數(shù)(使用負值表示沒有限制)
    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()
 
    //獲取配置信息構(gòu)造方法
    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();
        // 連接池最大連接數(shù)(使用負值表示沒有限制)
        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> {
        //設(shè)置序列化
        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

  • 運行結(jié)果

  • 運行結(jié)果.png

10氓涣、參考文章

參考Springboot2.0 使用redis @cacheable等注解緩存博客

11牛哺、工程架構(gòu)源代碼

Kotlin+SpringBoot與Redis整合工程源代碼

12 、總結(jié)與建議

  • 1 春哨、以上問題根據(jù)搭建 kotlin與Redis實際情況進行總結(jié)整理荆隘,除了技術(shù)問題查很多網(wǎng)上資料,通過自身進行學(xué)習(xí)之后梳理與分享赴背。

  • 2椰拒、 在學(xué)習(xí)過程中也遇到很多困難和疑點,如有問題或誤點凰荚,望各位老司機多多指出或者提出建議燃观。本人會采納各種好建議和正確方式不斷完善現(xiàn)況,人在成長過程中的需要優(yōu)質(zhì)的養(yǎng)料便瑟。

  • 3缆毁、 希望此文章能幫助各位老鐵們更好去了解如何在 kotlin上搭建RabbitMQ,也希望您看了此文檔或者通過找資料親身經(jīng)歷實操學(xué)習(xí)效果會更好到涂。

備注:此文章屬于本人原創(chuàng),歡迎轉(zhuǎn)載和收藏.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末脊框,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子践啄,更是在濱河造成了極大的恐慌浇雹,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屿讽,死亡現(xiàn)場離奇詭異昭灵,居然都是意外死亡,警方通過查閱死者的電腦和手機伐谈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門烂完,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人诵棵,你說我怎么就攤上這事抠蚣。” “怎么了履澳?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵嘶窄,是天一觀的道長缓屠。 經(jīng)常有香客問我,道長护侮,這世上最難降的妖魔是什么敌完? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮羊初,結(jié)果婚禮上滨溉,老公的妹妹穿的比我還像新娘。我一直安慰自己长赞,他們只是感情好晦攒,可當(dāng)我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著得哆,像睡著了一般脯颜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上贩据,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天栋操,我揣著相機與錄音,去河邊找鬼饱亮。 笑死矾芙,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的近上。 我是一名探鬼主播剔宪,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼壹无!你這毒婦竟也來了葱绒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤斗锭,失蹤者是張志新(化名)和其女友劉穎地淀,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拒迅,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡骚秦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年她倘,在試婚紗的時候發(fā)現(xiàn)自己被綠了璧微。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡硬梁,死狀恐怖前硫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情荧止,我是刑警寧澤屹电,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布阶剑,位于F島的核電站,受9級特大地震影響危号,放射性物質(zhì)發(fā)生泄漏牧愁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一外莲、第九天 我趴在偏房一處隱蔽的房頂上張望猪半。 院中可真熱鬧,春花似錦偷线、人聲如沸磨确。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽乏奥。三九已至,卻和暖如春亥曹,著一層夾襖步出監(jiān)牢的瞬間邓了,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工媳瞪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留驶悟,地道東北人。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓材失,卻偏偏與公主長得像痕鳍,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子龙巨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容