Spring Boot集成Redis 從Docker安裝到分布式Session共享

Spring從3.1開始仰冠,Spring引入了對Cache的支持蜕依,其使用方法和原理都類似于Spring對事務(wù)管理的支持典勇,Spring Cache是作用在方法上劫哼。核心思想,調(diào)用一個緩存方法時會把該方法的參數(shù)和返回值作為一組鍵值對存放在緩存中割笙,下次使用相同的參數(shù)來調(diào)用該方法時將直接讀取緩存中的內(nèi)容权烧。

SpringBoot提供了對Redis集成的組件包spring-boot-starter-data-redis(不要依賴spring-boot-starter-redis,他是舊版本)伤溉,該組件包同時依賴于spring-data-redis和lettuce般码,SpringBoot1.0默認(rèn)使用Jedis客戶端,2.0替換成了Lettuce乱顾。

Jedis在實現(xiàn)上是直連Redis服務(wù)板祝,多線程環(huán)境下非線程安全,除非使用連接池走净,為每個RedisConnection實例增加物理連接扔字。

Lettuce是一個可伸縮非阻塞且線程安全的Redis客戶端囊嘉,多個線程可以共享同一個RedisConnection温技,它利用netty NIO框架來高效地管理多個連接革为。

本文主要介紹Docker下安裝Redis、SpringBoot集成Redis以及具體的應(yīng)用分布式Session

Docker安裝Redis

鏡像選取

可通過DockerHub或者命令行選取鏡像舵鳞,Docker的安裝可參考Docker安裝

DockerHub選取

訪問https://hub.docker.com搜索redis即可震檩,https://hub.docker.com/search?q=redis&type=image

命令行選取

一般選取Starts最多的官方鏡像

docker search redis

可以查看到如下內(nèi)容(只截取了前三個)

kk@kk demo $ docker search redis
NAME                             DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
redis                            Redis is an open source key-value store that…   7926                [OK]
bitnami/redis                    Bitnami Redis Docker Image                      138                                     [OK]
sameersbn/redis                                                                  79                                      [OK]

拉取鏡像

默認(rèn)拉取最新版本的鏡像

docker pull redis

啟動容器

查看鏡像

docker images

可以查看到IMAGE ID(鏡像ID)

創(chuàng)建容器

docker run --name myredis -p 6379:6379 -d redis redis-server --appendonly yes
  • --name 設(shè)置命名(myredis)
  • -p 映射宿主機(jī)端口到容器端口
  • -d 后臺以守護(hù)進(jìn)程方式運行
  • redis 鏡像名(或者替換成鏡像ID均可)
  • redis-server --appendonly yes 在容器啟動執(zhí)行redis-server命令,打開redis持久化

查看容器

執(zhí)行命令蜓堕,查看正在運行的容器抛虏,可以觀察到已正常啟動

docker ps

啟動成功后顯示如下

kk@kk demo $ docker ps
CONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS              PORTS                                               NAMES
038d4475783a        redis                        "docker-entrypoint.s…"   7 seconds ago       Up 5 seconds        0.0.0.0:6379->6379/tcp                              myredis

查看容器日志

docker logs -f 038d4475783a

注意 038d4475783a 需替換成自己的redis容器ID
可以查看到以綁定6379端口

kk@kk demo $ docker logs -f 038d4475783a
1:C 18 Mar 2020 03:08:29.408 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 18 Mar 2020 03:08:29.408 # Redis version=5.0.8, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 18 Mar 2020 03:08:29.408 # Configuration loaded
1:M 18 Mar 2020 03:08:29.409 * Running mode=standalone, port=6379.
1:M 18 Mar 2020 03:08:29.409 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
1:M 18 Mar 2020 03:08:29.409 # Server initialized
1:M 18 Mar 2020 03:08:29.410 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
1:M 18 Mar 2020 03:08:29.410 * Ready to accept connections

SpringBoot集成Redis

簡易項目實戰(zhàn)

pom添加依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置文件application

server:
  port: 8078

spring:
  application:
    name: redis-session

  cache:
    type: redis
  # redis 配置
  redis:
    # 服務(wù)器地址
    host: 127.0.0.1
    # 服務(wù)器端口
    port: 6379
    # 服務(wù)器連接密碼(默認(rèn)為空)
    password:
    # Redis分片(默認(rèn)有16個分片,默認(rèn)為0)套才,在大型項目中建議使用0號分片存儲迂猴,select分片耗時較大
    database: 0
    # 連接超時時間
    timeout: 1000ms

redis簡易使用

    private final String cacheKey = "redis:cache:key:userid";

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @RequestMapping("/stringset")
    public String stringSetAction(@RequestParam String key, @RequestParam String value) {
        stringRedisTemplate.opsForValue().set(key, value);
        return stringRedisTemplate.opsForValue().get(key);
    }

基于注解的Redis

使用Spring Cache主要包含兩個步驟,

  1. 聲明某些方法使用緩存
  2. 配置Spring對Cache的支持
    和Spring對事務(wù)管理的支持一樣背伴,Spring對Cache的支持也有基于注解和基于XML配置兩種方式沸毁,以下將以注解方式進(jìn)行驗證

常用注解

@EnableCaching

開啟緩存功能,一般放在啟動類或者Redis的配置類上

@Cacheable

@Cacheable可以標(biāo)記在方法上傻寂,也可以標(biāo)記在類上息尺。當(dāng)標(biāo)記在方法上時表示該方法是支持緩存的,當(dāng)標(biāo)記在類上時表示該類所有的方法都支持緩存疾掰。

對于一個支持緩存的方法搂誉,Spring會在其被調(diào)用后將其返回值緩存起來,以保證下次使用相同的參數(shù)調(diào)用該方法時静檬,直接返回緩存中的結(jié)果炭懊。支持緩存的方法在對象內(nèi)部被調(diào)用時不會觸發(fā)緩存功能

Spring緩存方法的返回值是以鍵值對進(jìn)行緩存的,值就是方法的返回結(jié)果拂檩,對于鍵侮腹,Spring支持兩種策略,默認(rèn)策略和自定義策略广恢。

@Cacheable可以設(shè)置如下屬性

  • value:緩存名稱(必填)凯旋,指定緩存的命名空間
  • key:用于設(shè)置在命名空間中的緩存key值,可以使用SpEL表達(dá)式定義
  • unless:條件符合則不緩存
  • condition:條件符合則緩存

@CachePut

@CachePut也可以聲明一個方法支持緩存功能钉迷,與@Cacheable不同的是使用@CachePut標(biāo)注的方法在執(zhí)行前不會去檢查緩存中是否存在之前執(zhí)行的結(jié)果至非,而是每次都會執(zhí)行該方法,并將執(zhí)行結(jié)果以鍵值對的形式存入指定的緩存中

@CachePut可以設(shè)置如下屬性

  • value:緩存名稱(必填)糠聪,指定緩存的命名空間
  • key:用于設(shè)置在命名空間中的緩存key值荒椭,可以使用SpEL表達(dá)式定義
  • unless:條件符合則不緩存
  • condition:條件符合則緩存

@CacheEvict

@CacheEvict可以標(biāo)記在方法上,也可以標(biāo)記在類上舰蟆,當(dāng)標(biāo)記在一個類上時表示其中所有的方法的執(zhí)行都會觸發(fā)緩存的清除操作趣惠,

@CacheEvict可以設(shè)置如下屬性

  • value:緩存名稱(必填)狸棍,指定緩存的命名空間
  • key:用于設(shè)置在命名空間中的緩存key值,可以使用SpEL表達(dá)式定義
  • condition:條件符合則緩存

基于注解的項目實戰(zhàn)

pom添加依賴

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>

@Cacheable使用

注意:需要使用瀏覽器或postman進(jìn)行驗證味悄,使用IDEA插件RestService調(diào)用緩存不會生效


    private final String cacheKey = "redis:cache:key:userid";
    
    @RequestMapping("/cache")
    @Cacheable(value = cacheKey)
    public String cacheIndex() {
        System.out.println("set cache");
        return "set cache";
    }

只有首次訪問的時候再控制臺打印“set cache”草戈,之后直接返回Redis結(jié)果,不會在控制臺打印信息了

@CachePut使用

    private final String cacheKey = "redis:cache:key:userid";
    
    @RequestMapping("/put")
    @CachePut(value = cacheKey)
    public String putAction() {
        System.out.println("update cache");
        return "update cache";
    }

每次訪問會更新為本次的返回值

@CacheEvict使用

    private final String cacheKey = "redis:cache:key:userid";
    
    @RequestMapping("/del")
    @CacheEvict(value = cacheKey)
    public String delAction() {
        System.out.println("delete cache");
        return "delete cache";
    }

刪除緩存的內(nèi)容

共享Session

分布式系統(tǒng)中侍瑟,Session共享有很多解決方案唐片,存儲到緩存中是最常用的方案之一

Spring Session提供了一套創(chuàng)建和管理Servlet HttpSession的方案。Spring Session提供了集群Session(Clustered Sessions)功能涨颜,默認(rèn)采用外置的Redis來存儲Session數(shù)據(jù)费韭,以此來解決Session共享問題

Session項目實戰(zhàn)

pom依賴

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>

Session配置文件

@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30)
public class SessionConfig {
}

maxInactiveIntervalInSeconds:設(shè)置Session失效時間,使用Redis Session之后庭瑰,Spring Boot配置文件中的server.session.timeout屬性將不再生效

測試-獲取sessionID

注意:需要使用瀏覽器或postman進(jìn)行驗證星持,使用IDEA插件RestService調(diào)用緩存不會生效

@RestController
@RequestMapping("/session")
public class RedisSessionController {

    @RequestMapping("/uid")
    public String sessionAction(HttpSession session) {
        UUID uid = (UUID) session.getAttribute("uid");
        System.out.println("get " + uid);
        if (uid == null) {
            System.out.println("start set " + uid);
            uid = UUID.randomUUID();
        }
        System.out.println("set " + uid);
        session.setAttribute("uid", uid);
        return session.getId();
    }
}

可以多次調(diào)用觀察控制臺的打印信息

示例代碼

github示例代碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市弹灭,隨后出現(xiàn)的幾起案子督暂,更是在濱河造成了極大的恐慌,老刑警劉巖鲤屡,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件损痰,死亡現(xiàn)場離奇詭異,居然都是意外死亡酒来,警方通過查閱死者的電腦和手機(jī)卢未,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來堰汉,“玉大人辽社,你說我怎么就攤上這事∏萄迹” “怎么了滴铅?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長就乓。 經(jīng)常有香客問我汉匙,道長,這世上最難降的妖魔是什么生蚁? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任噩翠,我火速辦了婚禮,結(jié)果婚禮上邦投,老公的妹妹穿的比我還像新娘伤锚。我一直安慰自己,他們只是感情好志衣,可當(dāng)我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布屯援。 她就那樣靜靜地躺著猛们,像睡著了一般。 火紅的嫁衣襯著肌膚如雪狞洋。 梳的紋絲不亂的頭發(fā)上弯淘,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天,我揣著相機(jī)與錄音徘铝,去河邊找鬼耳胎。 笑死,一個胖子當(dāng)著我的面吹牛惕它,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播废登,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼淹魄,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了堡距?” 一聲冷哼從身側(cè)響起甲锡,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎羽戒,沒想到半個月后缤沦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡易稠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年缸废,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片驶社。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡企量,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出亡电,到底是詐尸還是另有隱情届巩,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布份乒,位于F島的核電站恕汇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏或辖。R本人自食惡果不足惜瘾英,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望孝凌。 院中可真熱鬧方咆,春花似錦、人聲如沸蟀架。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至煌集,卻和暖如春妓肢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背苫纤。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工碉钠, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人卷拘。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓喊废,卻偏偏與公主長得像,于是被迫代替她去往敵國和親栗弟。 傳聞我的和親對象是個殘疾皇子污筷,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,543評論 2 349

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