《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 blog.csdn.net/qq_27242695/article/details/112618063/ 「放牛放牛放牛」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

SpringBoot整合Redis

  • SpringBoot版本:2.x以上
  • 本案例版本:2.4.1

1 整合Redis

1.1 pom.xml添加依赖

<!--redis配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!--进行redisTemplate配置时需要此包-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>

<!--reids版本为1.4.1版本以上需要添加-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>

1.2 application.properties配置

1.2.1 哨兵连接配置

注意:redis高版本配置信息做了调整

SpringBoot 1.4版本之后配置如下

# 连接工厂使用的数据库索引,redis默认有16个db,索引0-15
spring.redis.database= 0
# 哨兵配置过程中,给主机命名的名字
spring.redis.sentinel.master=mymaster
# 哨兵,配置多个 都好隔开
spring.redis.sentinel.nodes=ip1:port1,ip2:port2,ip3:port3
# 登录redis服务器的密码,无设置密码可以不填写
spring.redis.password=password
# 给定时间池可以分配的最大连接数 使用负值为无限制
spring.redis.pool.max-active= 8
# 连接分配在池耗尽之前在抛出异常之前应阻止的最大时间量(连接池最大阻塞等待时间以毫秒为单位) 使用负值无限期地阻止
spring.redis.pool.max-wait= -1
# 连接池中的最大空闲连接 使用负值来表示无限数量的空闲连接
spring.redis.pool.max-idle= 8
# 连接池中的最小空闲连接 此设置只有在正值时才有效果
spring.redis.pool.min-idle= 0
# 连接超时(毫秒)
spring.redis.timeout=30000

SpringBoot 2.x版本配置如下

# 连接工厂使用的数据库索引,redis默认有16个db,索引0-15
spring.redis.database= 0
# 哨兵配置过程中,给主机命名的名字
spring.redis.sentinel.master=mymaster
# 哨兵,配置多个 都好隔开
spring.redis.sentinel.nodes=ip1:port1,ip2:port2,ip3:port3
# 登录redis服务器的密码,无设置密码可以不填写
spring.redis.password=password
# 给定时间池可以分配的最大连接数 使用负值为无限制
spring.redis.lettuce.pool.max-active= 8
# 连接分配在池耗尽之前在抛出异常之前应阻止的最大时间量(连接池最大阻塞等待时间以毫秒为单位) 使用负值无限期地阻止
spring.redis.lettuce.pool.max-wait= -1
# 连接池中的最大空闲连接 使用负值来表示无限数量的空闲连接
spring.redis.lettuce.pool.max-idle= 8
# 连接池中的最小空闲连接 此设置只有在正值时才有效果
spring.redis.lettuce.pool.min-idle= 0
# 连接超时(毫秒)
spring.redis.timeout=30000

1.2.2 单机版连接配置

SpringBoot 1.4版本之后配置如下

# 连接工厂使用的数据库索引,redis默认有16个db,索引0-15
spring.redis.database= 0
# Redis服务器主机
spring.redis.host=127.0.0.1
# redis服务器端口
spring.redis.port= 6379
# 登录redis服务器的密码,无设置密码可以不填写
spring.redis.password=password
# 给定时间池可以分配的最大连接数 使用负值为无限制
spring.redis.pool.max-active= 8
# 连接分配在池耗尽之前在抛出异常之前应阻止的最大时间量(连接池最大阻塞等待时间以毫秒为单位) 使用负值无限期地阻止
spring.redis.pool.max-wait= -1
# 连接池中的最大空闲连接 使用负值来表示无限数量的空闲连接
spring.redis.pool.max-idle= 8
# 连接池中的最小空闲连接 此设置只有在正值时才有效果
spring.redis.pool.min-idle= 0
# 连接超时(毫秒)
spring.redis.timeout=30000

SpringBoot 2.x之前版本配置如下

# 连接工厂使用的数据库索引,redis默认有16个db,索引0-15
spring.redis.database= 0
# Redis服务器主机
spring.redis.host=127.0.0.1
# redis服务器端口
spring.redis.port=6379
# 登录redis服务器的密码,无设置密码可以不填写
spring.redis.password=password
# 给定时间池可以分配的最大连接数 使用负值为无限制
spring.redis.lettuce.pool.max-active= 8
# 连接分配在池耗尽之前在抛出异常之前应阻止的最大时间量(连接池最大阻塞等待时间以毫秒为单位) 使用负值无限期地阻止
spring.redis.lettuce.pool.max-wait= -1
# 连接池中的最大空闲连接 使用负值来表示无限数量的空闲连接
spring.redis.lettuce.pool.max-idle= 8
# 连接池中的最小空闲连接 此设置只有在正值时才有效果
spring.redis.lettuce.pool.min-idle= 0
# 连接超时(毫秒)
spring.redis.timeout=30000

1.2.3 注意

当配置文件哨兵也单机版配置同时存在,哨兵连接机制优先。

注意SpringBoot版本,选择指定的配置。

1.3 Redis核心配置类-RedisConfig.java

/**
* Redis的核心配置类,这个类提供了两个方法(其实提供了两个bean,这两个bean会加载到spring的context里边,供使用者进行调用)
*/
@Configuration//这个标签,通常与@bean结合使用,当@bean使用到该类的方法上,代表将该方法做为一个bean交给了spring的context
@EnableCaching//允许我们使用缓存
public class RedisConfig {

@Bean//此时,将我们的redisTemplate加载到了我们的spring的上下文中,applicationContext
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
//为了自己开发方便,使用String,Object类型
RedisTemplate<String, Object> template = new RedisTemplate();
template.setConnectionFactory(factory);
//序列化配置,使用json解析任意的对象,将对象解析成可以序列化的对象
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//使用Mapper对象进行转义
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
//开始序列化对象
jackson2JsonRedisSerializer.setObjectMapper(om);

// String 类型的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//key采用String序列化的方式
template.setKeySerializer(stringRedisSerializer);
//hash采用String序列化的方式
template.setHashKeySerializer(stringRedisSerializer);
//value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
//hash的value序列化方式采用jackson
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}

@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
//1.序列话(一般用于key值)
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
//2.引入json串的转化类(一般用于value的处理)
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
//2.1设置objectMapper的访问权限
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//2.2指定序列化输入类型,就是将数据库里的数据按照一定类型存储到redis缓存中。
// objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);//最近升级SpringBoot,发现enableDefaultTyping方法过期过期了。可以使用下面的方法代替
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
//3.序列话配置,乱码问题解决以及我们缓存的时效性
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().
entryTtl(Duration.ofSeconds(1000)).//缓存时效性设置
serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)).//key序列化
serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).//value序列化
disableCachingNullValues();//空值不存入缓存
//4.创建cacheManager链接并设置属性
RedisCacheManager cacheManager = RedisCacheManager.builder(factory).cacheDefaults(config).build();
return cacheManager;
}
}

1.3.1 Spring提供的序列化器(使用方式自行百度)

  • Jackson2JsonRedisSerializer
  • JdkSerializationRedisSerializer
  • OxmSerializer
  • StringRedisSerializer
  • GenericToStringRedisSerializer
  • GenericJackson2JsonRedisSerializer

1.3.2 为什么要序列化?

在JAVA中,一切皆对象,而将对象的状态信息转为存储或传输的形式需要序列化。

2. 验证

2.1 单元测试redis中存储student对象

代码

@SpringBootTest(classes = DemoApplication.class)
public class RedisTest {

@Test
public void test1() {
Student student = new Student();
student.setName("学生1");
student.setSex("男");
student.setAge(18);
RedisUtil.set("student1", student);
System.out.println(RedisUtil.get("student1").toString());

}
}

控制台输出

redis控制台查看

xxx.xxx.xxx.xxx:6377[1]> get student1
"[\"com.exp.demo.dto.Student\",{\"name\":\"\xe5\xad\xa6\xe7\x94\x9f1\",\"sex\":\"\xe7\x94\xb7\",\"age\":18}]"

2 资源

2.1 工具类

工具类 RedisUtil

/**
* Redis工具类,使用之前请确保RedisTemplate成功注入
*
* @author lxq
*/

public class RedisUtil {

private RedisUtil() {
}

@SuppressWarnings("unchecked")
private static RedisTemplate<String, Object> redisTemplate = SpringUtil.getBean("redisTemplate", RedisTemplate.class);

/**
* 设置有效时间
* 单位默认秒
*
* @param key Redis键
* @param timeout 超时时间
* @return true=设置成功;false=设置失败
*/
public static boolean expire(final String key, final long timeout) {

return expire(key, timeout, TimeUnit.SECONDS);
}

/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @param unit 时间单位
* @return true=设置成功;false=设置失败
*/
public static boolean expire(final String key, final long timeout, final TimeUnit unit) {

Boolean ret = redisTemplate.expire(key, timeout, unit);
return ret != null && ret;
}

/**
* 删除单个key
*
* @param key 键
* @return true=删除成功;false=删除失败
*/
public static boolean del(final String key) {

Boolean ret = redisTemplate.delete(key);
return ret != null && ret;
}

/**
* 删除多个key
*
* @param keys 键集合
* @return 成功删除的个数
*/
public static long del(final Collection<String> keys) {

Long ret = redisTemplate.delete(keys);
return ret == null ? 0 : ret;
}

/**
* 存入普通对象
*
* @param key Redis键
* @param value 值
*/
public static void set(final String key, final Object value) {

redisTemplate.opsForValue().set(key, value);
}

// 存储普通对象操作

/**
* 存入普通对象
*
* @param key 键
* @param value 值
* @param timeout 有效期,单位秒
*/
public static void set(final String key, final Object value, final long timeout) {

redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
}

/**
* 获取普通对象
*
* @param key 键
* @return 对象
*/
public static Object get(final String key) {

return redisTemplate.opsForValue().get(key);
}

// 存储Hash操作

/**
* 往Hash中存入数据
*
* @param key Redis键
* @param filed Hash filed键
* @param value 值
*/
public static void hPut(final String key, final String filed, final Object value) {

redisTemplate.opsForHash().put(key, filed, value);
}

/**
* 往Hash中存入多个数据
*
* @param key Redis键
* @param filedMap Hash键值对
*/
public static void hPutAll(final String key, final Map<String, Object> filedMap) {

redisTemplate.opsForHash().putAll(key, filedMap);
}

/**
* 获取Hash中的数据
*
* @param key Redis键
* @param filed Hash filed键
* @return Hash中的对象
*/
public static Object hGet(final String key, final String filed) {

return redisTemplate.opsForHash().get(key, filed);
}

/**
* 获取多个Hash中的数据
*
* @param key Redis键
* @param fileds Hash filed键集合
* @return Hash对象集合
*/
public static List<Object> hMultiGet(final String key, final Collection<Object> fileds) {

return redisTemplate.opsForHash().multiGet(key, fileds);
}

// 存储Set相关操作

/**
* 往Set中存入数据
*
* @param key Redis键
* @param values 值
* @return 存入的个数
*/
public static long sSet(final String key, final Object... values) {
Long count = redisTemplate.opsForSet().add(key, values);
return count == null ? 0 : count;
}

/**
* 删除Set中的数据
*
* @param key Redis键
* @param values 值
* @return 移除的个数
*/
public static long sDel(final String key, final Object... values) {
Long count = redisTemplate.opsForSet().remove(key, values);
return count == null ? 0 : count;
}

// 存储List相关操作

/**
* 往List左侧中存入数据
*
* @param key Redis键
* @param value 数据
* @return 存入的个数
*/
public static long lPush(final String key, final Object value) {
Long count = redisTemplate.opsForList().leftPush(key, value);
return count == null ? 0 : count;
}

/**
* 往List右侧中存入数据
*
* @param key Redis键
* @param value 数据
* @return 存入的个数
*/
public static long rPush(final String key, final Object value) {
Long count = redisTemplate.opsForList().rightPush(key, value);
return count == null ? 0 : count;
}

/**
* 往List中左侧存入多个数据
*
* @param key Redis键
* @param values 多个数据
* @return 存入的个数
*/
public static long lPushAll(final String key, final Collection<Object> values) {
Long count = redisTemplate.opsForList().leftPushAll(key, values);
return count == null ? 0 : count;
}

/**
* 往List中左侧存入多个数据
*
* @param key Redis键
* @param values 多个数据
* @return 存入的个数
*/
public static long lPushAll(final String key, final Object... values) {
Long count = redisTemplate.opsForList().leftPushAll(key, values);
return count == null ? 0 : count;
}

/**
* 往List中右侧存入多个数据
*
* @param key Redis键
* @param values 多个数据
* @return 存入的个数
*/
public static long rPushAll(final String key, final Collection<Object> values) {
Long count = redisTemplate.opsForList().rightPushAll(key, values);
return count == null ? 0 : count;
}


/**
* 往List中右侧存入多个数据
*
* @param key Redis键
* @param values 多个数据
* @return 存入的个数
*/
public static long rPushAll(final String key, final Object... values) {
Long count = redisTemplate.opsForList().rightPushAll(key, values);
return count == null ? 0 : count;
}


/**
* 从List中获取begin到end之间的元素
*
* @param key Redis键
* @param start 开始位置
* @param end 结束位置(start=0,end=-1表示获取全部元素)
* @return List对象
*/
public static List<Object> listGetRange(final String key, final int start, final int end) {
return redisTemplate.opsForList().range(key, start, end);
}


/**
* 从List左侧弹出数据
*
* @param key Redis键
* @return 对象
*/
public static Object listGetL(final String key) {
return redisTemplate.opsForList().leftPop(key);
}


/**
* 从List右侧弹出数据
*
* @param key Redis键
* @return 对象
*/
public static Object listGetR(final String key) {
return redisTemplate.opsForList().rightPop(key);
}
}

SpringUtil

/**
* SpringBoot 容器工具类
*/
@Component
public class SpringUtil implements ApplicationContextAware {
/**
* 上下文对象实例
*/
private static ApplicationContext applicationContext;

@Override
@Autowired
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtil.applicationContext = applicationContext;
}

/**
* 获取applicationContext
* @return
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}

/**
* 通过name获取 Bean.
* @param name 参数传入要获取的实例的类名 首字母小写,这是默认的
* @return
*/
public static Object getBean(String name){
return getApplicationContext().getBean(name);
}

/**
* 通过class获取Bean.
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(Class<T> clazz){
return getApplicationContext().getBean(clazz);
}

/**
* 通过name,以及Clazz返回指定的Bean
* @param name
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(String name,Class<T> clazz){
return getApplicationContext().getBean(name, clazz);
}
}

2.2 代码

https://pan.baidu.com/s/1C8t8eCNwZzpSFHxJP0h3qQ 提取码: 7mp7

文章目录
  1. 1. SpringBoot整合Redis
    1. 1.1. 1 整合Redis
      1. 1.1.1. 1.1 pom.xml添加依赖
      2. 1.1.2. 1.2 application.properties配置
      3. 1.1.3. 1.3 Redis核心配置类-RedisConfig.java
    2. 1.2. 2. 验证
      1. 1.2.1. 2.1 单元测试redis中存储student对象
    3. 1.3. 2 资源
      1. 1.3.1. 2.1 工具类
    4. 1.4. 2.2 代码