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

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

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

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

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

本文主要介紹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)容(只截取了前三個(gè))

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

啟動(dòng)容器

查看鏡像

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 后臺(tái)以守護(hù)進(jìn)程方式運(yùn)行
  • redis 鏡像名(或者替換成鏡像ID均可)
  • redis-server --appendonly yes 在容器啟動(dòng)執(zhí)行redis-server命令,打開redis持久化

查看容器

執(zhí)行命令,查看正在運(yùn)行的容器,可以觀察到已正常啟動(dòng)

docker ps

啟動(dòng)成功后顯示如下

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

簡(jiǎn)易項(xiàng)目實(shí)戰(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個(gè)分片,默認(rèn)為0),在大型項(xiàng)目中建議使用0號(hào)分片存儲(chǔ),select分片耗時(shí)較大
    database: 0
    # 連接超時(shí)時(shí)間
    timeout: 1000ms

redis簡(jiǎn)易使用

    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主要包含兩個(gè)步驟,

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

常用注解

@EnableCaching

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

@Cacheable

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

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

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

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

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

@CachePut

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

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

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

@CacheEvict

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

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

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

基于注解的項(xiàng)目實(shí)戰(zhàn)

pom添加依賴

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

@Cacheable使用

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


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

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

@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";
    }

每次訪問會(huì)更新為本次的返回值

@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共享有很多解決方案,存儲(chǔ)到緩存中是最常用的方案之一

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

Session項(xiàng)目實(shí)戰(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失效時(shí)間,使用Redis Session之后,Spring Boot配置文件中的server.session.timeout屬性將不再生效

測(cè)試-獲取sessionID

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

@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)用觀察控制臺(tái)的打印信息

示例代碼

github示例代碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,556評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,778評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,218評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,436評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,969評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,795評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,993評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,229評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評(píng)論 1 286
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,687評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,990評(píng)論 2 374

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