Spring Boot集成Redis 从Docker安装到分布式Session共享

Spring从3.1开始,Spring引入了对Cache的支持,其使用方法和原理都类似于Spring对事务管理的支持,Spring Cache是作用在方法上。核心思想,调用一个缓存方法时会把该方法的参数和返回值作为一组键值对存放在缓存中,下次使用相同的参数来调用该方法时将直接读取缓存中的内容。

SpringBoot提供了对Redis集成的组件包spring-boot-starter-data-redis(不要依赖spring-boot-starter-redis,他是旧版本),该组件包同时依赖于spring-data-redis和lettuce,SpringBoot1.0默认使用Jedis客户端,2.0替换成了Lettuce。

Jedis在实现上是直连Redis服务,多线程环境下非线程安全,除非使用连接池,为每个RedisConnection实例增加物理连接。

Lettuce是一个可伸缩非阻塞且线程安全的Redis客户端,多个线程可以共享同一个RedisConnection,它利用netty NIO框架来高效地管理多个连接。

本文主要介绍Docker下安装Redis、SpringBoot集成Redis以及具体的应用分布式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

可以查看到如下内容(只截取了前三个)

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]

拉取镜像

默认拉取最新版本的镜像

docker pull redis

启动容器

查看镜像

docker images

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

创建容器

docker run --name myredis -p 6379:6379 -d redis redis-server --appendonly yes
  • --name 设置命名(myredis)
  • -p 映射宿主机端口到容器端口
  • -d 后台以守护进程方式运行
  • redis 镜像名(或者替换成镜像ID均可)
  • redis-server --appendonly yes 在容器启动执行redis-server命令,打开redis持久化

查看容器

执行命令,查看正在运行的容器,可以观察到已正常启动

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

简易项目实战

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:
    # 服务器地址
    host: 127.0.0.1
    # 服务器端口
    port: 6379
    # 服务器连接密码(默认为空)
    password:
    # Redis分片(默认有16个分片,默认为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对事务管理的支持一样,Spring对Cache的支持也有基于注解和基于XML配置两种方式,以下将以注解方式进行验证

常用注解

@EnableCaching

开启缓存功能,一般放在启动类或者Redis的配置类上

@Cacheable

@Cacheable可以标记在方法上,也可以标记在类上。当标记在方法上时表示该方法是支持缓存的,当标记在类上时表示该类所有的方法都支持缓存。

对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次使用相同的参数调用该方法时,直接返回缓存中的结果。支持缓存的方法在对象内部被调用时不会触发缓存功能

Spring缓存方法的返回值是以键值对进行缓存的,值就是方法的返回结果,对于键,Spring支持两种策略,默认策略和自定义策略。

@Cacheable可以设置如下属性

  • value:缓存名称(必填),指定缓存的命名空间
  • key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义
  • unless:条件符合则不缓存
  • condition:条件符合则缓存

@CachePut

@CachePut也可以声明一个方法支持缓存功能,与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中

@CachePut可以设置如下属性

  • value:缓存名称(必填),指定缓存的命名空间
  • key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义
  • unless:条件符合则不缓存
  • condition:条件符合则缓存

@CacheEvict

@CacheEvict可以标记在方法上,也可以标记在类上,当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作,

@CacheEvict可以设置如下属性

  • value:缓存名称(必填),指定缓存的命名空间
  • key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义
  • condition:条件符合则缓存

基于注解的项目实战

pom添加依赖

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

@Cacheable使用

注意:需要使用浏览器或postman进行验证,使用IDEA插件RestService调用缓存不会生效


    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结果,不会在控制台打印信息了

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

删除缓存的内容

共享Session

分布式系统中,Session共享有很多解决方案,存储到缓存中是最常用的方案之一

Spring Session提供了一套创建和管理Servlet HttpSession的方案。Spring Session提供了集群Session(Clustered Sessions)功能,默认采用外置的Redis来存储Session数据,以此来解决Session共享问题

Session项目实战

pom依赖

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

Session配置文件

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

maxInactiveIntervalInSeconds:设置Session失效时间,使用Redis Session之后,Spring Boot配置文件中的server.session.timeout属性将不再生效

测试-获取sessionID

注意:需要使用浏览器或postman进行验证,使用IDEA插件RestService调用缓存不会生效

@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();
    }
}

可以多次调用观察控制台的打印信息

示例代码

github示例代码

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

推荐阅读更多精彩内容