---随笔--Redis的学习以及在Spring Boot中的整合使用(RedisTemplate、Redisson分布式锁)
- 引言
- 1. 什么是Redis
- 2. Redis的数据结构
- 3. Redis其它常用命令
- 4. 小插曲之Redis面试常考
- 5. 正篇:Redis在Spring Boot中的使用!(着急的小伙伴可以直接跳这里看噢)
- 5.1 在maven文件中导入Redis依赖
- 5.2 配置Redis连接信息
- 5.3 使用RedisTemplate进行操作(记得运行redis server)
- 5.3.1 编写RedisTemplate配置类
- 5.3.2 注入使用RedisTemplate
- 5.3.3 Redis工具类完整代码(可自行添加方法)
- 5.4 测试Redis操作
- 5.5 Redisson分布式锁的使用
- 总结
引言
在现代Web应用开发中,性能和可扩展性至关重要。Redis作为一个高性能的内存数据结构存储系统,因其卓越的速度和丰富的功能而广受欢迎。而将Redis集成到Spring Boot项目中,可以显著提升应用程序的响应速度和处理能力。
本文将简要介绍Redis的用法及如何在Spring Boot中配置和使用Redis,涵盖基础配置和常见操作。通过阅读本文,您将掌握Redis的使用及如何在Spring Boot项目中高效使用Redis,优化应用性能,提升用户体验。 (若想直接跳到代码部分可以直接点目录哈~)
关于Redis的安装可以在网上查阅相关资料,这里就不费时间写如何安装了,还是蛮简单的,可以参考下‘明金同学’的这篇文章:Window下Redis的安装和部署详细图文教程,或者参考‘阿里社区’的这篇文章:Redis安装与配置指南:适用于Windows、Mac和Linux系统的详细教程,也可以参考’JAVA白大仙’的这篇文章:Windows版Docker安装Redis教程(保姆级),适合开发环境快速提供Redis服务
1. 什么是Redis
Redis(Remote Dictionary Server)是一个开源(BSD许可)的内存数据结构存储系统。它可以用作数据库、缓存和消息代理。Redis支持多种数据结构,例如字符串(String)、哈希表(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set)
和高级数据类型包括位图 (Bitmaps)、概率性数据结构 (HyperLogLog)、地理空间 (Geospatial)
。它的主要特点和功能包括:
- 高性能:Redis通过将数据存储在内存中,实现了非常高的读写速度,读写操作可以在毫秒级别内完成。
- 持久化:尽管Redis的数据主要存储在内存中,但它支持将数据异步地保存到磁盘,以实现持久化。支持RDB(快照)和AOF(Append Only File)两种持久化方式。
- 丰富的数据类型:Redis不仅支持简单的键值对,还支持复杂的数据结构,如列表、集合、有序集合和哈希表,这使得它在处理复杂数据时更加灵活。
- 原子操作:Redis提供了一组丰富的原子操作,这些操作保证了数据的一致性和完整性。
- 发布/订阅:Redis支持发布/订阅消息模式,可以用于构建实时消息系统。
- 主从复制:Redis支持主从复制,允许数据在多个Redis实例之间进行同步,从而提高数据的可用性和可靠性。
高可用性和分片:通过Redis Sentinel和Redis Cluster,可以实现高可用性和自动分片,从而支持更大规模的集群和更高的故障容忍度。
Redis广泛应用于缓存、会话存储、实时分析、消息队列和排行榜等场景,是提升Web应用性能和可扩展性的强大工具。
2. Redis的数据结构
Redis是一种高效的内存数据结构存储系统,支持多种数据结构和丰富的操作。以下是Redis的几种主要数据结构及其常见用法:
- 字符串 (String)
字符串是Redis中最基本的数据结构,每个键对应一个字符串值。
- 用法示例【
SET、GET、INCR、MGET 、MSET
】:
SET key "value" # 设置字符串值
GET key # 获取字符串值value
INCR key # 将字符串值自增1(要求值是整数)
MGET key1 key2 # 同时获取一个或多个 key 的值
MSET key1 key2 # 同时设置一个或多个 key-value 对
- 哈希 (Hash)
哈希是一种键值对集合,适用于存储对象。例如,用户信息。
- 用法示例【
HSET、HGET、HGETALL、HEXISTS、HKEYS、HVALS
】:
HSET user:1 name "Alice" # 设置哈希字段
HGET user:1 name # 获取哈希字段
HGETALL user:1 # 获取所有哈希字段和值
HEXISTS user:1 name # 检查指定字段是否存在于 Hash 中
HKEYS user:1 # 获取 Hash 中所有字段的列表
HVALS user:1 # 获取 Hash 中所有值的列表
- 列表 (List)
列表是一个有序的字符串集合,可以添加元素到列表的两端(左端和右端)。
- 用法示例【
LPUSH、RPUSH、LPOP、RPOP、LRANGE、LINDEX 、LSET 、LTRIM
】:
LPUSH tasks "task1" # 从左端插入元素
RPUSH tasks "task2" # 从右端插入元素
LPOP tasks # 从左端弹出元素
RPOP tasks # 从右端弹出元素
LRANGE tasks 0 -1 # 获取列表中所有元素
LINDEX tasks index # 通过索引获取列表中的元素
LSET tasks index value # 将列表中指定索引的元素设置为另一个值
LTRIM tasks start stop # 修剪(缩减)一个列表,使其只包含指定范围的元素
- 集合 (Set)
集合是一个无序的字符串集合,适用于存储不重复的数据。
- 用法示例【
SADD、SMEMBERS、SISMEMBER、SREM、SUNION、SINTER 、SDIFF 、SCARD、SRANDMEMBER、SPOP
】:
SADD myset "value1" # 添加元素到集合
SADD myset "value2"
SMEMBERS myset # 获取集合中的所有元素
SISMEMBER myset "value1" # 判断指定元素是否存在于集合中
SREM myset "value1" # 从集合中移除元素
SUNION set1 set2 # 返回两个或多个集合的并集
SINTER set1 set2 # 返回两个或多个集合的交集
SDIFF set1 set2 # 返回两个或多个集合的差集
SCARD myset # 获取集合中元素的数量
SRANDMEMBER myset 2 # 返回两个随机元素
SPOP myset 1 # 随机移除并返回一个元素
- 有序集合 (Sorted Set)
有序集合与集合类似,但每个元素都会关联一个评分(score),可以根据评分排序。
- 用法示例【
ZADD、ZRANGE(ZREVRANGE)、ZRANGEBYSCORE(ZREVRANGEBYSCORE)、ZREM、ZINCRBY 、ZSCORE
】:
ZADD myzset 1 "value1" # 添加元素及其评分
ZADD myzset 2 "value2"
ZRANGE myzset 0 -1 WITHSCORES # 获取所有元素及其评分,按分数升序排列
ZRANGEBYSCORE myzset min max WITHSCORES # 获取分数在 min 和 max 之间的元素及其分数
ZREM myzset "value1" # 移除元素
ZINCRBY myzset 2 "value2" # 将元素 "value2" 的分数增加 2
ZSCORE myzset "value2"
- 位图 (Bitmaps)
位图是一个字符串,在位级别上操作。可以将其视为一个大位数组。
- 用法示例【
SETBIT、GETBIT、BITCOUNT
】:
SETBIT bitmap 10 1 # 将第10位置为1
GETBIT bitmap 10 # 获取第10位的值
BITCOUNT bitmap # 统计位图中值为1的位数
- HyperLogLog
HyperLogLog是一种概率性数据结构,用于基数统计(即不重复元素的近似计数)。
- 用法示例【
PFADD、PFCOUNT
】:
PFADD hll "elem1" "elem2" # 添加元素到HyperLogLog
PFCOUNT hll # 获取不重复元素的近似计数
- 地理空间 (Geospatial)
Redis支持地理空间索引,允许存储地理位置及执行地理空间半径查询。
- 用法示例【
GEOADD、GEORADIUS
】:
GEOADD locations 13.361389 38.115556 "Palermo" # 添加地理位置
GEORADIUS locations 15 37 200 km # 查询半径内的位置
3. Redis其它常用命令
除了上述数据结构常用的命令外,Redis还提供了许多特殊的操作命令:
- TTL
TTL命令用于获取指定键的剩余生存时间(Time To Live
),即距离过期还有多少秒。
- 用法示例:
SET key "value" # 设置键 key 的值为 value
EXPIRE key 60 # 设置键 key 的过期时间为 60 秒
TTL key # 获取键 key 的剩余生存时间
- EXPIRE
EXPIRE命令用于设置指定键的过期时间,单位为秒。当键过期后,将自动被删除
。
- 用法示例:
SET session "token" # 设置会话 session 的值为 token
EXPIRE session 3600 # 设置 session 的过期时间为 3600 秒(1小时)
- DEL
DEL命令用于删除指定键及其对应的值
。
- 用法示例:
SET key "value" # 设置键 key 的值为 value
DEL key # 删除键 key
- KEYS
KEYS命令用于获取所有符合给定模式的键。
- 用法示例:
KEYS * # 获取所有键
KEYS user:* # 获取以 user: 开头的键
- SETNX
SETNX命令用于设置键的值,但仅在键不存在时才执行设置操作。如果键已经存在,则该命令不会执行任何操作。
- 用法示例:
SETNX key "value" # 当键 key 不存在时,设置其值为 value
这个命令通常用于设置分布式锁,确保同一时刻只有一个客户端能够获取锁。
- SETEX
SETEX命令用于设置键的值,并同时设置该键的过期时间
(单位为秒,原子操作
)。
- 用法示例:
SETEX key 60 "value" # 设置键 key 的值为 value,并同时设置过期时间为60秒
- PUBLISH 、SUBSCRIBE、UNSUBSCRIBE
使用SUBSCRIBE
命令让客户端订阅一个或多个频道
。当客户端订阅了频道后,它可以接收到所有发送到这些频道的消息。
SUBSCRIBE channel1
使用 PUBLISH
命令来发布
消息到一个指定的频道。任何订阅了该频道的客户端都将收到这条消息。
PUBLISH channel1 "Hello, World!"
订阅频道的客户端会实时接收到所有发布到这些频道的消息。消息的接收是自动的,一旦客户端订阅了频道,就会保持监听状态直到取消订阅。
如果客户端不再希望接收某个频道的消息,可以使用 UNSUBSCRIBE
命令来取消订阅
。
UNSUBSCRIBE channel1
- FLUSHDB
FLUSHDB命令用于清空当前数据库中的所有键,不影响其它数据库。
- 用法示例:
FLUSHDB # 清空当前数据库
- FLUSHALL
FLUSHALL命令用于清空所有数据库的所有键。
- 用法示例:
FLUSHALL # 清空所有数据库
- RENAME
RENAME命令用于修改键的名字。
- 用法示例:
SET mykey "value" # 设置键 mykey 的值
RENAME mykey newkey # 将 mykey 重命名为 newkey
- TYPE
TYPE命令用于获取键的数据类型。
- 用法示例:
TYPE mykey # 获取 mykey 的数据类型
- DBSIZE
DBSIZE命令用于获取当前数据库的键的数量。
- 用法示例:
DBSIZE # 获取当前数据库的键的数量
- PERSIST
PERSIST命令用于移除键的过期时间,使其变为持久键
。
- 用法示例:
SET mykey "value" EX 60 # 设置 mykey 的过期时间为60秒
PERSIST mykey # 移除 mykey 的过期时间
- INFO
INFO命令用于获取服务器的信息和统计数据。
- 用法示例:
INFO # 获取服务器的详细信息
INFO memory # 获取关于内存的统计信息
- MULTI、EXEC、DISCARD、WATCH
MULTI
:通过该命令来开启一个事务,后续的操作命令统统填进该事务队列中,直到执行或取消
EXEC
:该命令来执行所有队列中的命令
DISCARD
: 在执行 EXEC 之前决定不再继续事务,可以使用命令来取消事务
WATCH
:在开启事务之前,可以使用 WATCH 命令来监控一个或多个键。如果在执行事务之前这些键的值被修改,那么事务将不会执行,EXEC 命令将返回 nil。
WATCH balance # 监控余额,防止在事务开启前值被更改
GET balance
# 假设余额检查后足够进行某项操作
MULTI # 开启事务
DECRBY balance 100 #命令入队
LPUSH changelog "100 deducted from balance" #命令入队
#DISCARD # 取消上边事务队列中的事务
EXEC #将队列中的命令依次执行,保证事务
4. 小插曲之Redis面试常考
Redis也是后端开发技术面试的常考的一个知识,我们也是需要多了解了解的,有些理论知识也是挺有帮助的,有时可以很快地解决未知的bug。下面一起来看看Redis常考的面试题吧,浅浅过一下,查漏补缺。
- 基本概念和数据类型: 了解 Redis 是什么,它的特点和用途,为什么那么快。 掌握各种数据类型的使用和特点,如字符串(String),列表(List),集合(Set),有序集合(Sorted Set),哈希(Hash)。
- 命令熟悉度: 需要对常用的 Redis 命令有深入的了解,比如刚刚讨论的字符串和列表操作命令。 如何使用这些命令来实现具体的功能,比如实现队列、堆栈、消息发布/订阅等。
- 持久化机制: 理解 Redis 的持久化选项:RDB(快照)和 AOF(追加文件)。 知道它们的工作原理、优缺点以及如何配置。
- 事务处理: 如何在 Redis 中使用事务,了解 MULTI, EXEC, WATCH, 和 DISCARD 命令。 事务的特性,如原子性、隔离级别。
- 性能优化和监控: 熟悉如何优化 Redis 配置和性能。 了解监控工具和相关的性能指标。
- 高可用性与集群: Redis 的主从复制机制,故障转移和数据一致性。 Redis 集群的工作原理,如何设置和运维一个 Redis 集群。
- 特殊问题处理: 对缓存穿透、缓存雪崩和缓存击穿的理解和解决方案。
- 安全性: 如何安全地配置和使用 Redis,包括网络安全和数据安全。
Redis的面试题涵盖许多,更多的也可以参考下’涝山道士‘的【精选】30+Redis面试题整理(2024)附答案
5. 正篇:Redis在Spring Boot中的使用!(着急的小伙伴可以直接跳这里看噢)
5.1 在maven文件中导入Redis依赖
在pom.xml文件下的dependencies标签中添加以下标签:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
这里需要注意,添加了一个spring-boot-starter-web
的依赖,因为这个依赖里包含了Redis所需的序列化Jackson依赖,所以需要添加进来,如果不添加spring-boot-starter-web依赖,则需要手动再添加jackson-databind的相关依赖。
5.2 配置Redis连接信息
spring:
application:
name: myRedis
data:
redis:
host: localhost
port: 6379
database: 0 # Redis默认提供16个数据库(索引0-15),一般从第0个使用
password: <PASSWORD> # 如果有,没有则删除
# 使用lettuce作为连接客户端,若需要使用jedis需要再导入依赖并配置
lettuce:
# 连接池配置
pool:
max-active: 8 #最大活跃连接数为8
max-idle: 8 # 最大空闲连接数为8
min-idle: 0 # 最小空闲连接数为0
max-wait: -1ms # 最大等待时间为-1ms,即不限制等待时间
5.3 使用RedisTemplate进行操作(记得运行redis server)
5.3.1 编写RedisTemplate配置类
@Configuration
public class RedisConfig {
/***
* 这段代码的主要功能是创建和配置一个RedisTemplate bean,
* 在Redis数据库中设置键、值、哈希键和哈希值的序列化器,以与Redis数据库交互。
* 该代码配置了RedisTemplate与连接工厂和特定的序列化器,用于处理Redis中的键值对和哈希结构,允许以JSON格式存储和检索Redis数据库中的对象。
* @param factory 接受一个RedisConnectionFactory类型的参数factory,这个参数是由Spring自动注入的(yaml文件里配置了),用于连接到Redis数据库。
* @return
*/
@Bean
// 在控制台输出信息,表示正在使用自定义配置的 RedisTemplate
System.out.println("使用自定义的RedisTemplate配置");
// 创建一个 RedisTemplate<String, Object> 实例
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 设置 Redis 连接工厂,这是必须的,以便模板能够访问 Redis 服务器
template.setConnectionFactory(factory);
// 创建一个用于序列化字符串的序列化器
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 设置键(key)(value)的序列化方式。这里使用字符串序列化器,可以确保 key和value 的存储和读取不会出现乱码等问题
template.setKeySerializer(stringRedisSerializer);
template.setValueSerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
template.setHashValueSerializer(stringRedisSerializer);
// 初始化 RedisTemplate 实例的各项属性,确保它在返回前是完全可用的
template.afterPropertiesSet();
// 返回配置好的 RedisTemplate 实例
return template;
}
一开始我使用’GenericJackson2JsonRedisSerializer
’来对值进行序列化,但是后面测试的时候发现,在存储字符串的时候会把双引号""也存储进去,虽然读取的时候读出来的数据没有双引号,但是在客户端上get或者通过可视化查看值时还是不是很好看的,所以都使用‘StringRedisSerializer
’ 来序列化了,可能这也会带来一些问题,需要再研究了。
5.3.2 注入使用RedisTemplate
@Component
public class MyRedisUtils{
private final RedisTemplate<String, Object> redisTemplate;
//构造器注入
@Autowired
public MyRedisUtils(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
}
这里我使用了Spring框架推荐的构造器注入
方式,主要是这几点原因:
不变性和线程安全: 通过构造器注入,可以确保依赖对象在创建时就完全初始化。这样,redisTemplate 字段可以被声明为 final,意味着一旦赋值后就不可更改。这种不变性有助于保证线程安全,因为这个对象状态不会再发生变化。
依赖关系的清晰性: 构造器注入强制性地要求提供所有必需的依赖,否则对象无法被创建。这种方式使得依赖关系更加明显,不会隐藏在类的内部,有助于维护和理解代码。当查看构造函数时,可以清楚地看到类的所有依赖项,这比在类中间或底部查找注入点要直观得多。
与Spring框架的兼容性: 在现在的Spring主流版本上,如果类只有一个构造函数,Spring会默认使用这个构造函数进行依赖注入,即使没有显式地标注
@Autowired。这表明Spring团队推荐使用构造器注入,而且这种方式与Spring的自动装配机制非常兼容。测试的便利性: 使用构造器注入可以更容易地编写单元测试,因为可以在不启动Spring容器的情况下,通过直接传递构造参数来创建对象的实例。这使得测试更快、更独立,不依赖于Spring的配置或环境。
代码整洁与组织性: 构造器注入通常可以促使开发者编写更整洁、更有组织的代码。通过构造器集中管理依赖,可以避免在类中散布多个注入点,使类的结构更加清晰和模块化。
5.3.3 Redis工具类完整代码(可自行添加方法)
@Component
public class MyRedisUtils {
private final RedisTemplate<String, Object> redisTemplate;
@Autowired
public MyRedisUtils(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 设置指定key的值
*
* @param key 键
* @param value 值
*/
public void set(String key, Object value) {
System.out.println("set key: " + key + " value: " + value);
redisTemplate.opsForValue().set(key, value);
}
/**
* 获取指定key的值
*
* @param key 键
* @return 对应的值
*/
public Object get(String key) {
Object val = redisTemplate.opsForValue().get(key);
System.out.println("get key's value: " + val);
return val;
}
/**
* 删除指定key
*
* @param key 键
*/
public void delete(String key) {
System.out.println("delete key: " + key);
redisTemplate.delete(key);
}
/**
* 判断指定key是否存在
*
* @param key 键
* @return 存在则返回true,否则返回false
*/
public boolean exists(String key) {
Boolean hasKey = redisTemplate.hasKey(key);
System.out.println("whether exists key->" + key + ":" + hasKey);
return Boolean.TRUE.equals(hasKey);
}
/**
* 为指定key设置过期时间
*
* @param key 键
* @param timeout 过期时间(以秒为单位)
*/
public void expire(String key, long timeout) {
System.out.println("expire key: " + key + " timeout: " + timeout);
redisTemplate.expire(key, Duration.ofSeconds(timeout));
}
}
5.4 测试Redis操作
编写测试类:
@SpringBootTest
class MyRedisApplicationTests {
@Autowired
private MyRedisUtils myRedisUtils;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Test
public void testMyRedisUtilsIsNotNull() {
assertNotNull(myRedisUtils);
}
@Test
public void testSetAndGet() {
String key = "testKey";
String value = "testValue";
myRedisUtils.set(key, value);
assertEquals(value, myRedisUtils.get(key));
// 清理
myRedisUtils.delete(key);
}
@Test
public void testDelete() {
String key = "testKey";
myRedisUtils.set(key, "value");
assertTrue(myRedisUtils.exists(key));
myRedisUtils.delete(key);
assertFalse(myRedisUtils.exists(key));
}
@Test
public void testExpire() throws InterruptedException {
String key = "testKey";
myRedisUtils.set(key, "value");
myRedisUtils.expire(key, 1); // 设置1秒后过期
Thread.sleep(1500); // 等待超过1秒确保键已过期
assertNull(myRedisUtils.get(key));
}
}
执行结果:
5.5 Redisson分布式锁的使用
除了RedisTemplate能满足我们的一些日常需求外,Redisson还提供了分布式锁的解决方案,接下来我会使用RedissonClient来实现一个分布式锁来进行测试:
@Service
public class RedissonService {
private final RedissonClient redissonClient;
private volatile int count = 0; // 用于计数的变量
private static final Logger logger = LoggerFactory.getLogger(RedissonService.class);
@Autowired
public RedissonService(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
public void performTest() throws InterruptedException {
int threadNums = 100;
CountDownLatch countDownLatch = new CountDownLatch(threadNums);
for (int i = 0; i < threadNums; i++) {
new Thread(() -> {
// 使用RLock,这是Redisson的可重入锁
RLock lock = redissonClient.getLock("counterLock");
try {
// 尝试获取锁,等待获取锁最多10秒,超过10秒当前线程自动放弃;锁持有最长1秒,超时自动释放
if (lock.tryLock(10, 1, TimeUnit.SECONDS)) {
try {
// 计数器自增 1,通过redis锁来保证每次+1操作只有一个线程能进行
count += 1;
logger.info("计数器+1为:{}", count);
} finally {
// 释放锁
lock.unlock();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 设置中断标志
} finally {
// 计数器减1,直到计数器为0时
countDownLatch.countDown();
}
}).start();
}
countDownLatch.await(); // 等待所有线程完成,即当countDownLatch为0时完成,继续往下执行
logger.info("count = {}", count);
}
}
上述代码中同样使用了构造器注入的方式,将RedissonClient注入到方法中,主要需要理解下performTest()方法。
- 使用
CountDownLatch
:是为了让这100个线程全部执行完毕之后,才打印最终的计数count,不然循环中新创建的线程还没全部执行完就打印日志了,那结果肯定是不准的。 - 使用
RLock
:使用RLock而不是JUC包下的Lock,是因为RLock 是专门为使用 Redis 作为后端存储的环境设计的,用法也与Lock大差不差,但是RLock可以使用tryLock()
尝试获取锁,并在规定时间内获取锁后,又会在指定时间后释放掉锁,从而避免锁得不到释放的情况。 - count的类型:之所以可以不用AtomicInteger来进行自增,是因为AtomicInteger更消耗时间和资源,并且最主要的是在这里不需要保证count的原子性,因为每次count的修改都只有1个线程才能对它进行修改,是通过redis的锁来实现的,当执行当前线程后释放锁,下一个线程又可以操作count了,
测试结果:
@Test
public void testRedisson() throws InterruptedException {
redissonService.performTest();
}
当然,实现redis分布式锁的方式还有挺多,例如lua脚本: if redis.call(‘get’, KEYS[1]) == ARGV[1] then return redis.call(‘del’, KEYS[1]) else return 0 end、基于Setnx
的原始实现等等,就不细聊了,有兴趣的可以多去了解下^^
总结
Spring Boot对于Redis和Redis的整合还是蛮简单方便的,总的老说就是创建了Spring Boot项目后,导入redis数据库的依赖,同时也别忘记了导入spring-boot-web的依赖,因为里面包含了redis序列话需要用到的jackson库,之后配置RedisTemplate的配置文件,后面就可以注入RedisClient进行使用啦;Redisson的话也是同理,添加redisson依赖,注入RedissonClient就可以使用啦,还是很方便的!