Springboot整合Redis
1、添加依赖
添加redis需要的依赖:
spring-boot-starter-data-redis
完整的pom.xml文件
依赖中包含的依赖
这里我们直接引入了
spring-boot-starter-data-redis这个springBoot本身就已经提供好了的starter, 我们可以点击去看一下这个starter中包含了哪些依赖。
可以发现里面包含了spring-data-redis和 lettuce-core两个核心包,这就是为什么说我们的
spring-boot-starter-data-redis默认使用的就是lettuce这个客户端了。如果我们想要使用jedis客户端怎么办呢?就需要排除lettuce这个依赖,再引入jedis的相关依赖就可以了。那么为什么我们只需要通过引入不同的依赖就能让spring-data-redis可以自由切换客户端呢,这其实就涉及到了springBoot的自动化配置原理。
自动化配置原理
springBoot这个框架之所以可以通过各种starter无缝融合其他技术的一大主要原因就是springBoot本身的自动化配置功能。所谓自动化配置就是springBoot本身已经预先设置好了一些常用框架的整合类,然后通过类似于ConditionOn这样的条件判断注解,去辨别你的项目中是否有相关的类(或配置)了,进而进行相关配置的初始化。
SpringBoot预设的自动化配置类都位于spring-boot-autoconfigure这个包中,只要我们搭建了springBoot的项目,这个包就会被引入进来。
而这个包下就有一个RedisAutoConfiguration这个类,顾名思义就是Redis的自动化配置。在这个类中会引入
LettuceConnectionConfiguration 和
JedisConnectionConfiguration 两个配置类,分别对应lettuce和jedis两个客户端。
而这两个类上都是用了ConditionOn注解来进行判断是否加载。
jedis如下;
而由于我们的项目自动引入了lettuce-core,而没有引入jedis相关依赖,所以
LettuceConnectionConfiguration这个类的判断成立会被加载,而Jedis的判断不成立,所以不会加载。进而lettuce的配置生效,所以我们在使用的默认就是lettuce的客户端。
2、添加配置
我们需要配置连接redis所需的账号密码等信息,这里大家要提前安装好redis,保证我们的本机程序可以连接到我们的redis。
单机配置
常规配置如下: 在application.yml配置文件中配置 redis的连接信息。
如果有其他配置放到一起:
这样我们就可以直接在项目当中操作redis了。
集群配置
如果使用的是集群,那么使用如下配置方式:
配置连接池
但是有的时候我们想要给我们的redis客户端配置上连接池,就像我们连接mysql的时候也会配置连接池一样,目的就是增加对于数据连接的管理,提升访问的效率,也保证了对资源的合理利用。
那么我们如何配置连接池呢,这里大家一定要注意了,很多网上的文章中,介绍的方法可能由于版本太低,都不是特别的准确。 比如很多人使用spring.redis.pool来配置,这个是不对的(不清楚是不是老版本是这样的配置的,但是在
spring-boot-starter-data-redis中这种写法不对)。首先是配置文件,由于我们使用的lettuce客户端,所以配置的时候,在spring.redis下加上lettuce再加上pool来配置,具体如下:
如果使用的是jedis,就把lettuce换成jedis(同时要注意依赖也是要换的),但是仅仅这在配置文件中加入,其实连接池是不会生效的。这里大家一定要注意,很多同学在配置文件上加上了这段就以为连接池已经配置好了,其实并没有,还少了最关键的一步,就是要导入一个依赖,不导入的话这么配置也没有用。
之后连接池才会生效。我们可以做一个对比。 在导包前后,观察RedisTemplate对象的值就可以看出来。
导入之前:
导入之后:
导入之后,我们的连接池信息才有值,这也印证了我们上面的结论。具体的配置信息我们可以看一下源代码,源码中使用RedisProperties 这个类来接收redis的配置参数。
3、项目中使用
操作的话使用spring-data-redis中为我们提供的 RedisTemplate 这个类就可以操作了。我们先举个简单的例子,插入一个键值对(值为string)
使用redis+Lua脚本进行限流
说明:使用StringRedisTemplate类,不要用RedisTemplate类。
限流算法选择
1、固定窗口计数器:简单但有突刺问题
2、滑动窗口计数器:更平滑,但内存占用较高
3、令牌桶算法:允许突发流量
4、漏桶算法:流量整形,输出平滑
本方案采用滑动窗口计数器算法,既能避免固定窗口的突刺问题,又相对简单易实现。
技术架构
Redis:存储限流数据,利用其原子性操作
Lua脚本:保证限流逻辑的原子性执行
Spring Boot:应用框架
AOP:通过注解方式实现限流
实现原理
使用Redis的有序集合(ZSet)存储每个请求的时间戳,通过Lua脚本原子性地:
1、移除过期的请求记录
2、统计当前窗口内的请求数量
3、判断是否超过限制
4、添加新的请求记录
代码实现
1、添加依赖
2、限流注解定义
3、限流类型枚举
4、限流异常类
5、Lua脚本管理
6、Lua脚本文件
在
src/main/resources/lua/rate_limit.lua中创建:
7、限流工具类
8、AOP切面实现
9、全局异常处理
10、Redis配置
11、控制器示例
12、配置文件
优点
1、原子性:使用Lua脚本保证操作的原子性
2、高性能:基于Redis的高性能特性
3、灵活性:支持多种限流策略
4、易用性:通过注解方式使用,简单便捷
5、可扩展:支持自定义限流逻辑
接口
RedisSerializer
基本概念
RedisSerializer 是 Spring Data Redis 中的一个接口,它的主要作用是定义如何将 Java 对象序列化和反序列化为 Redis 存储格式(通常是字节数组)。由于 Redis 本身是一个键值存储系统,它并不理解 Java 对象的结构,因此需要通过序列化和反序列化机制将 Java 对象转化为适合存储的格式(如字符串、字节数组等),并在取回时恢复成原始的 Java 对象。
源码
方法
byte[] serialize(@Nullable T t)
将Java对象t序列化为字节数组
T deserialize(@Nullable byte[] bytes)
将字节数组 bytes 反序列化为Java对象
作用
处理Java对象与Redis 存储数据之间的转化。
常见的RedisSerializer 实现
1、StringRedisSerializer
用于将 Java 字符串(String)与 Redis 中的字符串数据进行序列化和反序列化。
2、JdkSerializationRedisSerializer
使用Java的原生序列化机制(java.io.Serializable)来序列化和反序列化对象,它可以用于将任何 Java 对象(只要它实现了 Serializable 接口)序列化为字节数组,但它的效率相对较低,且生成的字节数组可能较大。
3、Jackson2JsonRedisSerializer
使用 Jackson 序列化库将 Java 对象转换为 JSON 格式的字节数组,适用于存储 JSON 数据。它允许将复杂的 Java 对象(如自定义 POJO 类)转换为 JSON 字符串,然后再存储到 Redis 中。这样做的好处是数据格式可读性较高,并且能跨语言使用。
4、GenericJackson2JsonRedisSerializer
这个实现是
Jackson2JsonRedisSerializer 的一个改进,提供更为灵活和高效的 JSON 处理方式,支持泛型和复杂的类型。
5、ProtoBufRedisSerializer
使用 Google 的 Protocol Buffers(Protobuf)序列化格式,将对象序列化为紧凑的二进制格式。Protobuf 是一种高效的序列化方案,适用于需要高性能和低带宽的场景。
RedisOperations
基本概念
RedisOperations 接口是 Spring Data Redis 提供的一个核心接口,定义了对 Redis 数据库的各种操作方法。RedisOperations 提供了一套对 Redis 数据存取的高级抽象,使得开发者可以通过简单的接口调用,方便地执行 Redis 数据的读写、修改、删除等操作。
源码
作用
主要用于简化对 Redis 数据的操作,提供了对 Redis 各种数据类型(如 String、Hash、List、Set、ZSet 等)的通用支持。它在 Spring Data Redis 中起着重要的桥梁作用,封装了底层 Redis 访问逻辑,让开发者无需直接与 Redis 客户端 API 交互即可使用 Redis。
主要特性
数据访问的模板化
提供一个模板化的编程模型,开发者无需关心 Redis 连接管理、异常处理等底层细节。
支持Redis 数据结构
通过不同方法实现对 Redis 数据结构的操作,包括字符串、哈希表、列表、集合、有序集合等。
支持事务和管道
提供事务(Transaction)和管道(Pipeline)操作,以提高批量操作的效率。
泛型支持
允许通过泛型定义操作的 Key 和 Value 类型,提高了代码的类型安全性。
ValueOperations
基本概念
ValueOperations 接口是一个重要的操作接口,主要用于对 Redis 中的简单键值对(即 String 类型的数据)进行读写操作。ValueOperations 继承自 RedisOperations,它为我们提供了一些常用的操作方法,如 get(), set(), increment() 等,用于操作 Redis 中存储的值。
源码
作用
用于对 Redis 中的“简单值”类型(String 类型)进行操作。在 Redis 中,String 是最基础的数据类型,ValueOperations 提供了对这种数据类型的读写操作。
方法
V get(Object key)
用于从Redis中获取指定键(key)的值(value)。如果 Redis 中没有这个键,返回 null。
void set(K key, V value)
set 方法用于将一个值存储到 Redis 中。可以指定键值对存储的时间(通过 set 方法的重载)来实现过期时间。
void set(K key, V value, long timeout, TimeUnit unit);
除了设置键值对外,set 还支持设置值的过期时间(单位:秒)
V getAndDelete(K key)
会在返回 Redis 中指定键的值的同时删除该键
Long increment(K key, long delta);
用于对存储在 Redis 或其他支持的底层数据存储中的值执行增加操作的方法。increment() 方法用于增加存储在 Redis 中的某个 key 的值。它可以对整数类型的值执行增加操作。
参数:
key:进行增加操作的键
value:要增加的值。可以为正数、负数或零。
返回值:返回增加后的新值。如果 key 不存在,则会创建一个新的 key,并将其初始值设置为 delta。
使用场景:
1、计数器:通过将 delta 设置为正数,可以实现简单的递增计数器功能。
2、统计数据:通过增加 delta 来收集和统计数量。
3、限流策略:通过将 delta 设置为负数,可以实现限制访问次数。
示例代码:
在上述示例中,我们通过注入 ValueOperations 接口的实例,并使用 increment() 方法对指定的键执行增加操作。通过打印出增加后的新值,我们可以验证操作的有效性。请注意,increment() 方法只适用于存储整数类型的值,并且只能应用于支持的底层数据存储(例如 Redis)。如果存储的值不是整数类型,或者使用的底层数据存储不支持该操作,则会抛出相应的异常。
Long decrement(K key)
用于将值递减
List<V> multiGet(Collection<K> keys)
批量获取多个键对应的值
V getAndSet(K key, V value);
先获取键的当前值,然后将该值更新为指定值
BoundValueOperations
基本概念
BoundValueOperations接口是Spring Data Redis提供的一个用于操作 Redis String数据类型的工具接口。它通过绑定(Bound)某个特定的Redis键(Key),简化了对Redis数据的操作,避免开发者反复指定相同的Key,从而提高了代码的可读性和简洁性。
源码
作用
1、键绑定
将操作绑定到指定的Redis键,后续方法调用无需再传递键名。
2、简化操作
针对同一键的多次操作(如 set、get、append)代码更简洁。
3、支持链式调用
支持方法链式调用,提升代码可读性。
特点
1、针对特定Key 进行操作
一旦绑定了一个 Key,所有操作都将默认针对该 Key。
2、适用于String 数据类型
BoundValueOperations 主要用来操作Redis的String类型数据。
3、简化代码
避免重复输入Key,提高代码的简洁性和可读性。
方法
使用步骤
1、注入Redis模板:使用 StringRedisTemplate(字符串操作)或自定义的 RedisTemplate。
2、绑定键:通过 boundValueOps(key) 创建 BoundValueOperations 实例。
3、执行操作:调用 set、get 等方法操作键的值。
示例代码
1、使用 StringRedisTemplate(字符串操作)
2、使用RedisTemplate(对象序列化)
假设存储 User 对象,需配置 JSON 序列化器:
适用场景
1、计数器:如统计页面访问量
2、缓存对象:如缓存用户信息。
3、动态配置:如管理全局开关。
RedisCallback
基本概念
它的作用是提供一个回调接口,用于执行 Redis 命令。RedisCallback 使得你可以在执行 Redis 操作时更加灵活地控制连接的获取、命令的执行以及返回结果的处理。
源码
方法
T doInRedis(RedisConnection connection)
这是 RedisCallback 的核心方法,所有的 Redis 操作都通过该方法执行。它接受一个 RedisConnection 对象,RedisConnection 是 Spring Data Redis 中用于与 Redis 服务器进行交互的接口。
doInRedis 方法中的代码会在 Redis 连接中执行,通常会通过 RedisConnection 提供的方法来操作 Redis 数据。
作用
解耦 Redis 操作的细节,提供一个灵活的方式来执行复杂的 Redis 操作。它通常与 RedisTemplate 配合使用,在执行 Redis 操作时提供一个回调机制。
回调机制的核心作用
解耦 Redis 操作:通过使用回调接口,Redis 操作的具体实现和业务逻辑得以解耦。业务逻辑只需要定义如何处理数据,而不需要关心如何操作 Redis。
灵活性:通过 RedisCallback,你可以直接访问底层的 Redis 连接(RedisConnection),从而执行任意 Redis 命令。这提供了更大的灵活性,特别是当 Spring Data Redis 提供的高级方法无法满足需求时。
管理 Redis 连接:RedisCallback 允许你在回调中直接操作 RedisConnection,这意味着你可以更细粒度地控制 Redis 连接的使用,包括手动管理事务、批量操作等。
如何使用RedisCallback
通常,RedisTemplate 提供了许多封装好的方法,可以方便地进行 Redis 操作。但如果你需要执行一些较为复杂的操作,或者想要对底层的 Redis 连接进行细粒度的控制,可以使用 RedisCallback。Spring Data Redis 中的 RedisTemplate 提供了 execute 方法,可以接受一个 RedisCallback,并在该回调中执行 Redis 命令。
通过这种方式,RedisTemplate 会提供一个 Redis 连接,传递给 RedisCallback,然后回调中的代码会在该连接上执行。
使用RedisCallback的场景
1、执行复杂的Redis 操作
RedisTemplate 提供的标准方法(如 opsForValue(), opsForList() 等)不能完全满足需求,这时你可以使用 RedisCallback 来执行自定义的 Redis 操作。例如,执行一些低级的 Redis 命令,或者在操作期间需要特别处理 Redis 连接。
假设你想执行一个原子操作,在一个 Redis 事务中进行多个命令,或者在 Redis 脚本中执行命令,RedisCallback 提供了这样的能力。
在这个例子中,我们通过 RedisCallback 执行了一个 Redis 事务,其中包含了两个 SET 命令。multi() 开始事务,exec() 提交事务。通过 RedisCallback,你可以直接访问 Redis 连接并执行这些命令。
类
RedisAutoConfiguration
基本概念
在Spring Boot中,RedisAutoConfiguration 类是自动化配置Redis的核心组件。它简化了Redis客户端的集成,通过条件化配置机制自动创建必要的Bean。
源码
核心注解
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
RedisProperties
基本概念
RedisProperties 是 Spring Boot 中用于配置 Redis 连接和相关设置的配置属性类。它是 Spring Boot 自动配置机制的重要组成部分,让开发者可以通过 application.properties 或 application.yml 文件来配置 Redis 相关参数。
RedisProperties 类位于
org.springframework.boot.autoconfigure.data.redis 包中,使用 @ConfigurationProperties 注解,前缀为 "spring.redis"。
源码
主要属性配置
基础连接配置
host: Redis 服务器主机地址,默认为 localhost
port: Redis 服务器端口,默认为 6379
password: Redis 服务器密码
database: 要连接的数据库索引,默认为 0
url: 完整的 Redis 连接 URL,格式如 redis://user:password@host:port/database
连接池配置(Pool)
RedisProperties 包含一个内部类 Pool,用于配置连接池参数:
max-active: 连接池最大连接数,默认为 8
max-idle: 连接池最大空闲连接数,默认为 8
min-idle: 连接池最小空闲连接数,默认为 0
max-wait: 连接池最大阻塞等待时间,默认为 -1ms(无限等待)
集群配置(Cluster)
用于 Redis 集群模式的配置
nodes: 集群节点列表,格式为 host:port
max-redirects: 集群重定向的最大次数
哨兵配置(Sentinel)
用于 Redis 哨兵模式的配置:
master: 哨兵监控的主节点名称
nodes: 哨兵节点列表
password: 哨兵密码
超时配置
timeout: 连接超时时间
connect-timeout: 连接建立超时时间
read-timeout: 读取超时时间
SSL配置
ssl: 是否启用 SSL 连接
ssl.bundle: SSL 证书配置
配置示例
客户端类型配置
Lettuce 配置
Lettuce 是 Spring Boot 2.x 默认的 Redis 客户端:
Jedis 配置
自定义配置类
你也可以创建自定义的配置类来进一步定制 Redis 配置:
使用场景
1、单机Redis 配置
最常见的使用场景
2、Redis 集群配置
生产环境中的高可用部署
3、Redis 哨兵配置
主从复制环境下的故障转移
4、连接池优化
根据应用负载调整连接池参数
5、SSL 安全连接
在安全要求较高的环境中使用
总结
通过 RedisProperties,Spring Boot 提供了非常灵活和完整的 Redis 配置选项,能够满足从开发到生产环境的各种需求。
RedisCacheManager
基本概念
在 Spring Data Redis 中,RedisCacheManager 是用于管理和操作 Redis 缓存的核心类,它实现了 Spring 的 CacheManager 接口,能够将缓存数据存储到 Redis 中,并提供了对缓存的创建、配置和管理的功能。
源码
方法
public static RedisCacheManager create(RedisConnectionFactory connectionFactory)
public static RedisCacheManagerBuilderbuilder(RedisConnectionFactory connectionFactory)
配置RedisCacheManager
1、基于默认配置
2、自定义全局配置
3、为不同缓存设置独立配置
高级特性
1、缓存事务支持
通过配置 enableTransactionSupport 启用事务
2、缓存统计信息
在配置中启用统计
3、动态创建缓存
如果缓存未在初始化时配置,RedisCacheManager 会根据默认配置自动创建新的缓存实例。
RedisCacheConfiguration
基本概念
RedisCacheConfiguration是Spring Data Redis中用于配置Redis缓存行为的不可变配置类。它定义了Redis缓存的各种特性,如序列化方式、过期时间、key前缀等。
主要功能
1、缓存配置
2、序列化配置
重要方法
RedisCacheConfiguration.defaultCacheConfig()
获取默认配置
RedisCacheConfiguration.defaultCacheConfig(classLoader)
指定类加载器的默认配置
.entryTtl(Duration.ofMinutes(30))
固定过期时间
.entryTtl(MyCustomTtlFunction.INSTANCE)
动态过期时间(Spring Data Redis 3.2+)
.disableCachingNullValues()
禁止缓存null值
.disableKeyPrefix()
禁用key前缀
.enableTimeToIdle()
启用空闲时间过期(TTI)
默认设置
总结
RedisCacheConfiguration是Spring Redis缓存的核心配置类,通过它可以:
1、设置缓存过期策略
2、配置序列化方式
3、控制缓存行为(如是否缓存null值)
4、定义key前缀规则
5、实现不同缓存区域的差异化配置
它采用建造者模式,支持链式调用,使配置过程简洁明了。合理配置这个类是使用Spring Redis缓存的关键。
RedisTemplate
基本概念
RedisTemplate是Spring Data Redis框架提供的一个核心类,用于在Java应用程序中与Redis数据库进行交互。RedisTemplate提供了一组方法和功能,使得在应用程序中使用Redis变得更加方便。
源码
作用
1、连接Redis数据库
RedisTemplate封装了与Redis数据库的连接和底层通信的细节。它提供了配置和管理与Redis服务器的连接,包括连接池、主从复制、哨兵模式等。通过RedisTemplate,可以在Java应用程序中建立与Redis数据库的连接,并执行各种操作。
2、数据存取操作
RedisTemplate提供了一系列方法来进行Redis数据库的数据存取操作。例如,可以使用RedisTemplate向Redis数据库存储键值对数据,通过指定键获取对应的值,以及删除指定的键值对等。RedisTemplate还支持各种常用的Redis数据结构,例如列表、集合、有序集合等的操作。
3、数据序列化与反序列化
RedisTemplate支持将Java对象与Redis数据库中的数据进行序列化和反序列化。它使用了默认的序列化方式,并且也提供了扩展性,可以自定义序列化方式。通过RedisTemplate,在应用程序中可以将Java对象转换为字节数组或字符串存储到Redis数据库中,同时也可以从Redis数据库中获取的数据反序列化为Java对象。
4、事务支持
RedisTemplate还提供了事务支持,可以将多个Redis操作组合成一个事务进行执行。通过使用RedisTemplate的事务功能,可以保证一系列操作要么全部成功,要么全部失败,实现了对Redis数据库的原子性操作。
5、异步操作
RedisTemplate可以支持异步操作,通过返回ListenableFuture对象来处理异步结果。这使得在高并发场景下能够更好地利用系统资源,提高性能和响应速度。
方法
public ValueOperations<K, V> opsForValue()
该方法返回一个ValueOperations对象,用于对Redis中的字符串类型数据进行操作。通过ValueOperations对象,可以进行存储、获取、删除等操作。
opsForList()
该方法返回一个ListOperations对象,用于对Redis中的列表类型数据进行操作。通过ListOperations对象,可以进行插入、获取、删除等操作。
opsForSet()
该方法返回一个SetOperations对象,用于对Redis中的集合类型数据进行操作。通过SetOperations对象,可以进行添加、获取、删除等操作。
opsForZSet()
该方法返回一个ZSetOperations对象,用于对Redis中的有序集合类型数据进行操作。通过ZSetOperations对象,可以进行添加、获取、删除等操作。
execute()
可以使用自定义的Redis命令来执行各种高级操作,例如事务、流水线、Lua脚本等。通过execute()方法,可以执行一些特定的Redis命令。
public Boolean hasKey(K key)
确定指定的key是否存在
public Set<K> keys(K pattern)
用于根据给定的表达式查询 Redis中的 key。
public <HK, HV> HashOperations<K, HK, HV> opsForHash()
public Long getExpire(K key)
用于获取指定键的过期时间(剩余时间)
返回值:返回指定键的过期时间(剩余时间),单位为秒。
如果键不存在或者键没有设置过期时间,返回值为-1。
如果键存在并且设置了过期时间,返回值为剩余的过期时间(即距离键过期还有多少秒)。
Long getExpire(K key, TimeUnit timeUnit)
用于获取指定键的过期时间(剩余时间),已给定的时间单位显示。
public BoundValueOperations<K, V> boundValueOps(K key)
获取一个用于操作 Redis 中 String 类型数据的操作对象,通过这个对象可以进行数据的读取、写入、删除等操作。
StringRedisTemplate
基本概念
StringRedisTemplate是Spring Data Redis框架提供的一个特化版本的RedisTemplate类,专门用于简化对Redis数据库中的字符串类型数据进行操作。StringRedisTemplate在底层与Redis数据库进行交互时,默认使用字符串的序列化方式。
源码
RedisTemplate 和StringRedisTemplate区别
1、序列化方式
2、泛型类型
3、适用场景
4、配置示例
RedisTemplate(JSON 序列化)
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 使用 JSON 序列化器
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
return template;
}
}
StringRedisTemplate(默认配置)
5、核心操作对比
写入数据
读取数据
总结
StringRedisTemplate是Spring Data Redis框架中专门用于简化对Redis数据库中的字符串类型数据进行操作的特化版本的RedisTemplate类。它封装了与Redis数据库的连接和通信细节,提供了一组方法和功能,方便地进行字符串类型数据的存取、批量操作、事务支持以及键的操作。通过StringRedisTemplate,可以更加便捷地在Java应用程序中操作Redis数据库中的字符串数据。
DefaultRedisScript
基本概念
DefaultRedisScript 是 Spring Data Redis 中用于执行 Lua 脚本的核心实现类,它实现了 RedisScript 接口。这个类为在 Redis 中执行 Lua 脚本提供了便捷的封装和管理功能。
源码
核心属性
scriptText
String 类型,存储 Lua 脚本的文本内容
scriptSource
Resource 类型,脚本资源对象(可以是文件、classpath 资源等)
sha1
String 类型,脚本的 SHA1 哈希值,用于脚本缓存
resultType
Class<T> 类型,脚本执行结果的类型
构造方法
publicDefaultRedisScript()
public DefaultRedisScript(String script, Class<T> resultType)
核心方法
publicStringgetScriptAsString()
获取脚本文件
public void setScriptText(String scriptText)
设置脚本文件
public void setScriptSource(Resource scriptSource)
设置脚本资源
public void setResultType(Class<T> resultType)
设置结果类型
使用方式
1. 直接创建脚本对象
2、从文件加载脚本
对应的 Lua 脚本文件 rate-limit.lua:
使用场景
1、原子性操作
需要保证多个 Redis 命令的原子性执行
2、复杂业务逻辑
在 Redis 端执行复杂的数据处理逻辑
3、性能优化
减少网络往返次数,提高执行效率
4、分布式锁
实现高性能的分布式锁机制
5、限流算法
实现滑动窗口、令牌桶等限流算法
6、数据聚合
在 Redis 端进行数据统计和聚合操作
总结
通过 DefaultRedisScript,开发者可以充分利用 Redis 的 Lua 脚本功能,实现高效、原子性的数据操作。
工具类封装
我们在前面的代码中已经通过RedisTemplate成功操作了redis服务器,比如set一个字符串,我们可以使用
来put一个String类型的键值对。而redis中可以支持 string, list, hash,set, zset五种数据格式,这五种数据格式的常用操作都在RedisTemplate这个类中进行了封装。 操作string类型就是用opsForValue,操作list类型是用listOps, 操作set类型是用setOps等等。我们可以通过查看RedisTemplate这个类中的源码来了解大致有哪些功能。
而这些功能都在这一个类中,使用起来其实并不是很方便,所有一般情况下,我们都是单独封装一个工具类,来把常用的一些方法进行抽象。操作的时候直接通过工具类来操作。
redis序列化
基本概念
redis序列化就是我们把对象存入到redis中到底以什么方式存储的,可以是二进制数据,可以是xml也可以是json。比如说我们经常会将POJO 对象存储到 Redis 中,一般情况下会使用 JSON 方式序列化成字符串存储到 Redis 中 。
Redis本身提供了以下的序列化的方式:
GenericToStringSerializer: 可以将任何对象泛化为字符串并序列化
Jackson2JsonRedisSerializer: 跟
JacksonJsonRedisSerializer实际上是一样的
JacksonJsonRedisSerializer: 序列化object对象为json字符串(高版本已经没有这个类了)
JdkSerializationRedisSerializer: 序列化java对象
StringRedisSerializer: 简单的字符串序列化
如果我们存储的是String类型,默认使用的是StringRedisSerializer 这种序列化方式。如果我们存储的是对象,默认使用的是
JdkSerializationRedisSerializer,也就是Jdk的序列化方式(通过ObjectOutputStream和ObjectInputStream实现,缺点是我们无法直观看到存储的对象内容)。
我们可以根据redis操作的不同数据类型,设置对应的序列化方式。
通过观察RedisTemplate的源码我们就可以看出来,默认使用的是
JdkSerializationRedisSerializer,这种序列化最大的问题就是存入对象后,我们很难直观看到存储的内容,很不方便我们排查问题。
而一般我们经常使用的对象序列化方式是:
Jackson2JsonRedisSerializer,设置序列化方式的主要方法就是我们在配置类中自己来创建RedisTemplate对象,并在创建的过程中指定对应的序列化方式。
这样使用的时候,就会按照我们设置的json序列化方式进行存储,我们也可以在redis中查看内容的时候方便的查看到属性值。
GenericToStringSerializer类
基本概念
GenericToStringSerializer 是一个通用的序列化器,用于将任意类型的对象转换为字符串并存储到Redis,同时支持从字符串反序列化为目标对象。
源码
核心作用
1、对象序列化
将Java对象转换为字符串。
2、对象反序列化
将字符串转换回Java对象。
3、灵活性
支持自定义转换逻辑,适用于多种数据类型。
4、可读性强
存储的字符串数据可直接通过Redis命令行查看。
配置示例
在Spring Boot中配置 RedisTemplate 使用 GenericToStringSerializer
使用场景
1、自定义转换逻辑
如将日期对象转换为特定格式的字符串:
2、跨语言兼容性
其他语言(如Python、Node.js)可直接读取Redis中的字符串数据。
3、数据可读性
存储的字符串数据可直接通过Redis命令行查看:
注意事项
1、性能优化
(2)对于高频操作的数据类型,优先选择高效的序列化器(如 StringRedisSerializer)。
(2)避免在 GenericToStringSerializer 中频繁切换转换逻辑。
2、Null值处理
serialize(null) 返回 null。
deserialize(null) 返回 null
3、编码一致性
默认使用UTF-8编码,如需其他编码(如GBK),需自定义序列化器:
GenericJackson2JsonRedisSerializer
基本概念
GenericJackson2JsonRedisSerializer 是 Spring Data Redis 中基于 Jackson 的通用 JSON 序列化器,用于将 Java 对象序列化为 JSON 存储到 Redis,并能反序列化回原始对象类型。这是一个类型安全的序列化器,它会在 JSON 中保存对象的类型信息,反序列化时能恢复到原始类型,无需预先知道对象类型。
核心特点
1、类型保持
序列化时保存类型信息,反序列化时恢复原始类型
2、通用性
可以处理任意 Java 对象,不需要预定义类型
3、JSON 格式
人类可读的 JSON 格式存储
4、Jackson 底层
基于成熟的 Jackson 库
序列化原理
序列化过程
反序列化过程
基础使用
1、配置RedisTemplate
2、自定义配置
注意事项
1、安全考虑
2、版本兼容性
最佳实践
1、类型安全
利用类型信息保证序列化/反序列化的正确性
2、性能考虑
对于高频访问的简单对象,考虑使用专用序列化器
3、存储大小
JSON 格式比二进制序列化占用更多空间,但可读性更好
4、安全配置
在生产环境中适当限制反序列化的类型范围
5、版本管理
合理处理对象结构的演进和兼容性
总结
GenericJackson2JsonRedisSerializer 是Spring Data Redis 中最灵活的序列化器,特别适合需要缓存多种类型对象的场景。
Jackson2JsonRedisSerializer类
基本概念
Jackson2JsonRedisSerializer 是 Spring Data Redis 提供的一个序列化器,它利用 Jackson 将 Java 对象转换成 JSON 格式,并能将 JSON 数据反序列化还原为 Java 对象。
源码
核心作用
1、对象序列化
将Java对象转换为JSON字符串。
2、对象反序列化
将JSON字符串转换回Java对象。
3、跨语言兼容
JSON是通用的数据格式,便于与其他语言(如Python、JavaScript)交互。
4、可读性强
存储的JSON数据可直接通过Redis命令行查看。
配置示例
注意事项
1、类型信息丢失
默认情况下,JSON中不包含类信息,反序列化时需明确目标类型。
2、泛型支持
反序列化泛型对象时,需通过 TypeReference 指定类型:
3、性能优化
使用 ObjectMapper 的单例模式,避免重复创建。
启用缓存(
ObjectMapper.enableDefaultTyping())
4、Null值处理
serialize(null) 返回 null。
deserialize(null) 返回 null。
与GenericJackson2JsonRedisSerializer的区别
使用示例
1、Jackson2JsonRedisSerializer
配置:
存储与读取
2、GenericJackson2JsonRedisSerializer
配置:
存储与读取
序列化结果对比
1、Jackson2JsonRedisSerializer
存储的json串
2、GenericJackson2JsonRedisSerializer
存储的json串
适用场景
1、Jackson2JsonRedisSerializer
明确目标类型:如缓存固定类型的对象(如 User、Order)。
性能优化:不携带类型信息,序列化结果更小。
2、GenericJackson2JsonRedisSerializer
动态反序列化:如通用缓存服务,存储多种类型的对象。
泛型支持:如缓存 List<User>、Map<String, User> 等泛型对象。
JdkSerializationRedisSerializer类
基本概念
JdkSerializationRedisSerializer 是 Spring Data Redis 中基于 JDK 原生序列化机制的序列化器,使用 Java 内置的 ObjectInputStream 和 ObjectOutputStream 进行对象序列化。
这是 Spring Data Redis 的默认序列化器,使用 Java 原生的二进制序列化格式,要求被序列化的对象必须实现 Serializable 接口。
特点
1、JDK 原生
基于 Java 标准序列化机制
2、二进制格式
序列化后是二进制数据,不可读
3、类型完整性
保持完整的对象类型信息
4、向后兼容
JDK 序列化的标准兼容性
5、性能适中
序列化速度一般,但很稳定
序列化要求
1、实现Serializable 接口
2、处理非序列化字段
基础配置
1、默认配置
2、显式配置
3、自定义类加载器
最佳实践
1、显式serialVersionUID
总是显式声明版本号
2、异常处理
妥善处理序列化/反序列化异常
3、版本管理
谨慎处理类结构变更
4、安全考虑
注意反序列化安全问题
5、性能监控
监控序列化性能和存储空间
6、适用场景
适合内部 Java 系统,复杂对象关系场景
总结
JdkSerializationRedisSerializer 是最传统和稳定的序列化方案,特别适合纯 Java 环境下的复杂对象缓存场景。
StringRedisSerializer类
基本概念
StringRedisSerializer 是用于处理字符串数据的序列化器,适用于键和值均为字符串的场景。
源码
核心作用
1、字符串序列化
将Java的 String 类型转换为字节数组(默认使用UTF-8编码),以便存储到Redis。
2、字符串反序列化
将Redis中的字节数组转换回Java的 String 类型。
3、轻量高效
相比其他序列化器(如
JdkSerializationRedisSerializer),不添加额外元数据,性能更高。
配置示例
在Spring Boot中配置 RedisTemplate 使用 StringRedisSerializer
与其他序列化器的对比
注意事项
1、仅支持字符串类型
若尝试序列化非字符串对象(如 User),会抛出 ClassCastException。
2、编码一致性
默认使用UTF-8编码,如需其他编码(如GBK),需自定义序列化器:
3、Null值处理
serialize(null) 返回 null。
deserialize(null) 返回 null。
4、性能优化
高频字符串操作场景下,优先选择 StringRedisSerializer,避免序列化开销。
问题
1、java.util.LinkedHashMap cannot be cast to com.feisuanyz.pojo.domain.UserDO
通常是因为反序列化时无法确定目标类型,导致JSON数据被默认解析为LinkedHashMap而非预期的UserDO
问题原因分析
1、JSON序列化器未携带类型信息
1、默认行为:若使用
GenericJackson2JsonRedisSerializer但未显式激活类型信息(Type Hint),序列化的JSON中不会包含对象的类信息(如@class字段)。
2、反序列化结果:当从Redis读取数据时,JSON解析器因缺乏类型信息,只能将JSON对象解析为通用的LinkedHashMap,而非具体的UserDO类。
2、配置不一致
序列化与反序列化不匹配:可能在存储时使用了不携带类型信息的序列化器,而反序列化时却期望得到具体类型。
解决方法
方法一:显式配置序列化器携带类型信息
通过配置
GenericJackson2JsonRedisSerializer激活类型信息,确保序列化的JSON中包含类路径信息。
步骤一:自定义ObjectMapper
步骤二:验证存储的JSON数据
存储的JSON会包含类信息(如@class字段)
步骤三:读取数据
方法二:使用指定类型的序列化器
直接使用
Jackson2JsonRedisSerializer并指定目标类型(如UserDO.class),避免依赖类型信息
步骤一:配置指定类型的序列化器
步骤二:存储和读取数据
注意事项
1、序列化一致性
(1)确保存储和读取时使用相同的序列化器配置。
(2)若使用
GenericJackson2JsonRedisSerializer,必须激活类型信息(activateDefaultTyping)。
2、泛型匹配
如果使用RedisTemplate<String, Object>,反序列化时需确保实际类型与期望类型一致。
3、数据兼容性
若Redis中已存在无类型信息的旧数据,需清理或迁移数据,否则反序列化仍会失败。