SpringBoot 整合 redis 实现高效缓存,实战分享!
一、摘要
在前几篇文章中,我们详细介绍了 redis 的一些功能特性以及主流的 java 客户端 api 使用方法。
在当前流行的微服务以及分布式集群环境下,Redis 的使用场景可以说非常的广泛,能解决集群环境下系统中遇到的不少技术问题,在此列举几个使用 redis 经常用到的功能!
- 分布式缓存:在分布式的集群架构中,将缓存存储在内存中会出现很多的问题,比如用户回话信息,因为这部分信息需要与其他机器共享,此时利用 Redis 可以很好的解决机器之间数据共享的问题,缓存也是 Redis 中使用最多的场景
- 分布式锁:在高并发的情况下,我们需要一个锁来防止并发带来的脏数据,Java 自带的锁机制显然对进程间的并发并不好使,此时利用 Redis 的单线程特性,实现分布式锁控制
- 接口限流:在集群环境下,可以利用 redis 的分布式自增ID功能,精准的统计每个接口在指定时间内的请求次数,利用这个特性,可以定向限制某个接口恶意频刷
当然 Redis 的使用场景并不仅仅只有这么多,还有很多未列出的场景,如发布/订阅,分布锁集合等。
现实中我们大部分的微服务项目,都是基于 SpringBoot 框架进行快速开发,在 SpringBoot 项目中我们应该如何使用 Redis 呢?
代码实践如下!
二、代码实践
2.1、添加 redis 相关依赖包
实际上,在 SpringBoot 项目中,使用redis
非常简单,开发者只需要在项目中添加如下的依赖即可!
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
在之前的 redis 系列文章中,我们知道官方推荐的 java 版本的 redis 客户端,一共有三个,分别是Jedis
、Lettuce
和Redisson
,其中大部分场景下,使用Jedis
或者Lettuce
就足够了。
在 SpringBoot 1.x 版本里面,spring-boot-starter-data-redis
默认集成的客户端是Jedis
;从 SpringBoot 2.x 开始,spring-boot-starter-data-redis
默认集成的客户端是Lettuce
。
以springBoot-2.1.0
版本为例,我们打开spring-boot-starter-data-redis
依赖配置,核心配置如下!
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starters</artifactId>
<version>2.1.0.RELEASE</version>
</parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.1.0.RELEASE</version>
<name>Spring Boot Data Redis Starter</name>
<!--省略其他配置...-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.1.2.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>jcl-over-slf4j</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>5.1.2.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
可以很清晰的看到,spring-boot-starter-data-redis
默认集成的客户端是Lettuce
。
2.2、配置 redis 相关连接信息
依赖包添加完成之后,我们还需要在application.properties
全局配置文件中,添加相关的 redis 配置信息。
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制) 默认 8
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=-1
# 连接池中的最大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认 0
spring.redis.lettuce.pool.min-idle=0
最后,我们来跑一个最简单的单元测试,看看是否能联通(确保 redis 的服务端已经启动)。
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = RedisApplication.class)
public class TestRedis {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
public void test() throws Exception {
String uuid = UUID.randomUUID().toString();
stringRedisTemplate.opsForValue().set(uuid, uuid, 60, TimeUnit.SECONDS);
System.out.println(stringRedisTemplate.opsForValue().get(uuid));
}
}
如果控制台输出正常,说明基本配置已经完成,如果有错误,看错误信息然后依次排查!
2.3、重新配置 RedisTemplate 的序列化策略
SpringBoot 为我们提供了一个高度封装的RedisTemplate
类来操作redis
的各个命令,开发者无需关心具体的客户端 api 问题,通过RedisTemplate
提供的方法,就可以操作redis
,方便开发者可以无成本替换 java 客户端。
当我们存储对象的时候,RedisTemplate
默认采用的是 Jdk 提供的序列化工具库,该工具有个要求,缓存的对象必须显式实现序列化接口,才能保存。
通常情况下,我们会自定义RedisTemplate
的序列化策略,采用Jackson
将对象转成json
,查询的时候将json
转成对象。
具体实现如下:
@Configuration
public class RedisTemplateConfig {
/**
* 默认是JDK的序列化策略,这里配置redisTemplate采用的是Jackson2JsonRedisSerializer的序列化策略
* @param factory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer<Object> jacksonSeial = new Jackson2JsonRedisSerializer<>(Object.class);
// 使用Jackson序列号对象
ObjectMapper objectMapper = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
objectMapper.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会抛出异常
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(objectMapper);
// 使用RedisTemplate对象
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 配置连接工厂
template.setConnectionFactory(factory);
// 使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
// 值采用json序列化
template.setValueSerializer(jacksonSeial);
// 使用StringRedisSerializer来序列化和反序列化redis的hash-key值
template.setHashKeySerializer(new StringRedisSerializer());
// 值采用json序列化
template.setHashValueSerializer(jacksonSeial);
//执行后续方法
template.afterPropertiesSet();
return template;
}
}
2.4、RedisTemplate 使用介绍
我们知道,redis 提供的数据结构很丰富,支持字符串、哈希表、列表、集合、有序集合等数据类型的存储,RedisTemplate
对这五种数据结构分别定义了不同的操作类,具体如下:
ValueOperations
:操作最简单的K-V
数据ListOperations
:操作list
类型的数据HashOperations
:操作hash
类型的数据SetOperations
:操作set
类型的数据ZSetOperations
:操作zset
类型的数据
相关的 api 介绍如下!
初次访问:反爬虫,人机识别
