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è)步驟,
- 聲明某些方法使用緩存
- 配置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)的打印信息