Spring Boot整合Redis的完整步骤
作者:Jian 发布时间:2023-06-03 03:21:56
目录
前言
一、Spring Boot对Redis的支持
二、实战
1、添加依赖
2、redis配置
3、实现序列化
4、创建Redis连接工厂,同时注册Bean
5、完整的RedisConfig配置类
三、测试
1、编写redis工具类
2、Person实体类
3、编写测试类
4、测试结果
总结
前言
实际 开发 中 缓存 处理是必须的,不可能我们每次客户端去请求一次 服务器 ,服务器每次都要去 数据库 中进行查找,为什么要使用缓存?说到底是为了提高系统的运行速度。将用户频繁访问的内容存放在离用户最近,访问速度最 快的 地方,提高用户的响 应速度,今天先来讲下在 springboot 中整合 redis 的详细步骤。
一、Spring Boot对Redis的支持
Spring对Redis的支持是使用Spring Data Redis来实现的,一般使用Jedis或者lettuce(默认),Java客户端在 org.springframework.boot.autoconfigure.data.redis(Spring Boot 2.x) 中redis的自动配置 AutoConfigureDataRedis
RedisAutoConfiguration提供了RedisTemplate与StringRedisTemplate(只针对键值都是字符型的数据)模板,其中注解 @ConditionalOnMissingBean 是关键,表明该Bean如果在Spring中已经存在,则忽略,如果没有存在则在此处注册由Spring管理,也就是说我们可以“重写”该bean,实现自己的RedisTemplate与StringRedisTemplate,事实上,是要需要重写的,理由如下:
没有实现我们所需要的序列化;
泛型总是<Object, Object>,大部分场景我们更需要<String, Object>。
@Bean
@ConditionalOnMissingBean(
name = {"redisTemplate"}
)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
二、实战
1、添加依赖
1)需要spring-boot-starter-cache依赖,管理缓存
<!-- Spring Boot Cache -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2)需要spring-boot-starter-data-redis依赖(注:spring boot 2.x改为在data下),支持redis:主要以为Jedis客户端为主,排除默认的lettuce作为客户端的依赖
<!-- Redis Cache -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!-- 排除lettuce包,使用jedis代替-->
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
3)需要jedis-client依赖(注:Redis Client 3版本以上会报错与spring-boot-starter-data-redis冲突,最好使用2.9.x),使用jedis作为客户端
<!-- Redis Client 3版本以上会报错与spring-boot-starter-data-redis冲突 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
2、redis配置
创建RedisConfig配置类,增加@Configuration注解,同时开启缓存管理支持(添加注解@EnableCaching),继承CachingConfigurerSupport重写key生成策略
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* 生成key的策略:根据类名+方法名+所有参数的值生成唯一的一个key
* @return
*/
@Bean
@Override
public KeyGenerator keyGenerator() {
return (Object target, Method method, Object... params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
};
}
}
之后使用的application.yml配置文件,其中这里已经选择jedis作为客户端。
# redis 配置
redis:
port: 6379
# Redis服务器连接密码(默认为空)
password:
host: xxx.xxx.xxx.xxx
database: 0
jedis:
pool:
#连接池最大连接数(使用负值表示没有限制)
max-active: 300
# 连接池中的最小空闲连接
max-idle: 100
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: 10000
# 连接超时时间(毫秒)
timeout: 5000
同时读取配置属性,注入JedisPoolConfig
/**
* redis配置属性读取
*/
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.database}")
private int database;
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.max-wait}")
private long maxWaitMillis;
@Value("${spring.redis.jedis.pool.max-active}")
private int maxActive;
/**
* JedisPoolConfig配置
* @return
*/
@Bean
public JedisPoolConfig jedisPoolConfig() {
log.info("初始化JedisPoolConfig");
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(maxActive);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
jedisPoolConfig.setMaxIdle(maxIdle);
return jedisPoolConfig;
}
3、实现序列化
针对RedisTemplate或StringRedisTemplate进行序列化,同时重写注册Bean
RedisTemplate默认使用JdkSerializationRedisSerializer,StringRedisTmeplate默认使用的是StringRedisSerializer。但都是不符合实际要求的
/**
* 重新实现RedisTemplate:解决序列化问题
* @param redisConnectionFactory
* @return
*/
@Bean
@SuppressWarnings({"rawtype", "unchecked"})
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<String, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 设置任何字段可见
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 设置不是final的属性可以转换
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
log.info("objectMapper: {}", om);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson序列化方式
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson序列化方式
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
template.setEnableTransactionSupport(true);
return template;
}
/**
* 重新实现StringRedisTmeplate:键值都是String的的数据
* @param redisConnectionFactory
* @return
*/
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
template.setConnectionFactory(redisConnectionFactory);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson序列化方式
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson序列化方式
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
4、创建Redis连接工厂,同时注册Bean
注意Spring Boot 1.x与Spring Boot 2.x的区别,已在代码中注释表明,Spring Boot 1.x使用的是JedisConnectionFactory 。而Spring Boot 2.x使用的是RedisStandaloneConfiguration ,之后传入JedisConnectionFactory返回Bean
/**
* 注入RedisConnectionFactory
* @return
*/
@Bean
public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
log.info("初始化JedisConnectionFactory");
/* 在Spring Boot 1.x中已经过时,采用RedisStandaloneConfiguration配置
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);
jedisConnectionFactory.setHostName(host);
jedisConnectionFactory.setDatabase(database);*/
// JedisConnectionFactory配置hsot、database、password等参数
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(host);
redisStandaloneConfiguration.setPort(port);
redisStandaloneConfiguration.setDatabase(database);
// JedisConnectionFactory配置jedisPoolConfig
JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jedisPoolConfigBuilder =
(JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();
jedisPoolConfigBuilder.poolConfig(jedisPoolConfig);
return new JedisConnectionFactory(redisStandaloneConfiguration);
}
5、完整的RedisConfig配置类
/**
*
* @author jian
* @date 2019/4/14
* @description
* 1) RedisTemplate(或StringRedisTemplate)虽然已经自动配置,但是不灵活(第一没有序列化,第二泛型为<Object, Object>不是我们想要的类型)
* 所以自己实现RedisTemplate或StringRedisTemplate)
* 2) 采用RedisCacheManager作为缓存管理器
*
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
private static final Logger log = LoggerFactory.getLogger(RedisConfig.class);
/**
* redis配置属性读取
*/
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.database}")
private int database;
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.max-wait}")
private long maxWaitMillis;
@Value("${spring.redis.jedis.pool.max-active}")
private int maxActive;
/**
* JedisPoolConfig配置
* @return
*/
@Bean
public JedisPoolConfig jedisPoolConfig() {
log.info("初始化JedisPoolConfig");
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(maxActive);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
jedisPoolConfig.setMaxIdle(maxIdle);
return jedisPoolConfig;
}
/**
* 注入RedisConnectionFactory
* @return
*/
@Bean
public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
log.info("初始化JedisConnectionFactory");
/* 在Spring Boot 1.x中已经过时,采用RedisStandaloneConfiguration配置
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);
jedisConnectionFactory.setHostName(host);
jedisConnectionFactory.setDatabase(database);*/
// JedisConnectionFactory配置hsot、database、password等参数
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(host);
redisStandaloneConfiguration.setPort(port);
redisStandaloneConfiguration.setDatabase(database);
// JedisConnectionFactory配置jedisPoolConfig
JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jedisPoolConfigBuilder =
(JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();
jedisPoolConfigBuilder.poolConfig(jedisPoolConfig);
return new JedisConnectionFactory(redisStandaloneConfiguration);
}
/**
* 采用RedisCacheManager作为缓存管理器
* @param connectionFactory
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheManager redisCacheManager = RedisCacheManager.create(connectionFactory);
return redisCacheManager;
}
/**
* 生成key的策略:根据类名+方法名+所有参数的值生成唯一的一个key
* @return
*/
@Bean
@Override
public KeyGenerator keyGenerator() {
return (Object target, Method method, Object... params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
};
}
/**
* 重新实现RedisTemplate:解决序列化问题
* @param redisConnectionFactory
* @return
*/
@Bean
@SuppressWarnings({"rawtype", "unchecked"})
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<String, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 设置任何字段可见
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 设置不是final的属性可以转换
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
log.info("objectMapper: {}", om);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson序列化方式
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson序列化方式
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
template.setEnableTransactionSupport(true);
return template;
}
/**
* 重新实现StringRedisTmeplate:键值都是String的的数据
* @param redisConnectionFactory
* @return
*/
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
template.setConnectionFactory(redisConnectionFactory);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson序列化方式
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson序列化方式
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
}
三、测试
1、编写redis工具类
虽然RedisTemplate与StringRedisTemplate模板有提供的主要数据访问方法:
opsForValue():操作只有简单属性的数据
opsForList():操作含有List的数据
opsForSet():操作含有set的数据
opsForHash():操作含有hash的数据
opsForZSet():操作含有有序set类型ZSet的数据
但是相关比较抽象,实现起来比较复杂,有必要进一步封装,比如使用redisTmeplate中的简单value的get操作:
Object result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
但是封装之后,相对客户端用户来说比较明了
/**
* 读取缓存
*
* @param key
* @return
*/
public Object get(final String key) {
Object result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
return result;
}
完整的简单工具类如下:
@Component
public class RedisUtils {
@Autowired
private RedisTemplate redisTemplate;
/**
* 批量删除对应的value
*
* @param keys
*/
public void remove(final String... keys) {
for (String key : keys) {
remove(key);
}
}
/**
* 批量删除key
*
* @param pattern
*/
public void removePattern(final String pattern) {
Set<Serializable> keys = redisTemplate.keys(pattern);
if (keys.size() > 0) {
redisTemplate.delete(keys);
}
}
/**
* 删除对应的value
*
* @param key
*/
public void remove(final String key) {
if (exists(key)) {
redisTemplate.delete(key);
}
}
/**
* 判断缓存中是否有对应的value
*
* @param key
* @return
*/
public boolean exists(final String key) {
return redisTemplate.hasKey(key);
}
/**
* 读取缓存
*
* @param key
* @return
*/
public Object get(final String key) {
Object result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
return result;
}
/**
* 写入缓存
*
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 写入缓存
*
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value, Long expireTime) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
2、Person实体类
需要注意的是一定要实现序列化,并且有序列化版本ID
public class Person implements Serializable {
private final long serialVersionUID = 1L;
private String id;
private String name;
private int age;
private String gender;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Person{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
3、编写测试类
Redis工具类Spring已经做了管理(增加@Compent注解),使用很简单,只需要注入RedisUtils即可
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisTest {
@Autowired
private RedisUtils redisUtils;
@Test
public void test(){
Person person = new Person();
person.setAge(23);
person.setId("001");
person.setName("Zhangsan");
redisUtils.set("person-001", person);
System.out.println(redisUtils.get("person-001"));
}
}
4、测试结果
在IDE控制台中:
在登录客户端后查看value值
总结
来源:https://www.cnblogs.com/jian0110/p/10833056.html


猜你喜欢
- 由于又开了新机器所以又要重新布置Jenkins从老项目拷贝过来,发现Job Import Plugin 这个插件更新了,和以前的有些出入所以
- 在使用线程池的时候,发现除了execute()方法可以执行任务外,还发现有一个方法submit()可以执行任务。submit()有3个参数不
- 简单介绍如果把单链表的最后一个节点的指针指向链表头部,而不是指向NULL,那么就构成了一个单向循环链表,通俗讲就是让尾节点指向头结点。单向环
- 1、局部变量在方法或语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。局部变量声明在方法、构造方
- 一般来说,在更新DataTable或是DataSet时,如果不采用SqlParameter,那么当输入的Sql语句出现歧义时,如字符串中含有
- Mybatis表现关联关系比hibernate简单,没有分那么细致one-to-many、many-to-one、one-to-one。而是
- 一、项目简述本系统功能包括:数据统计、收件录入、发件录入、到件录入、派件录入、问题件录入、退件录入、留仓录入、装车录入、发车录入、到车录入、
- 不废话了,直接给大家贴代码了。class term { String str; int id; &
- 关于《JavaCV的摄像头实战》系列《JavaCV的摄像头实战》顾名思义,是使用JavaCV框架对摄像头进行各种处理的实战集合,这是欣宸作为
- 目录1、在java中,无论在何处调用,使用静态属性必须以类名做前缀。2、若有定义语句: int a=10 ; double b=3.14 ;
- 目录1.加载本地Word2.以只读模式加载Word3.从流加载Word【程序环境】Windows 10Visual Studio 2017W
- 一、概述数据透视表(Pivot Table)是一种交互式的表,可以进行某些计算,如求和与计数等,可动态地改变透视表版面布置,也可以重新安排行
- 在Java里面,可以用复制语句”A=B”给基本类型的数
- 前言MyBatis提供了9种动态SQL标签:trim、where、set、foreach、if、choose、when、otherwise、
- PS:本文包含了大部分strings函数的说明,并附带举例说明。本来想自己整理一下的,发现已经有前辈整理过了,就转了过来。修改了原文一些源码
- 概述什么是 Spring WebFlux, 它是一种异步的, 非阻塞的, 支持背压(Back pressure)机制的Web 开发框架. 要
- 最近在做项目的时候有用到对两个集合中的元素进行对比求其交集的情况,因为涉及到的数据量比较大,所以在进行求两个集合中元素交集的时候,就应该考虑
- 这两天我写了一个测试c++异常处理机制的例子,感觉有很好的示范作用,在此贴出来,给c++异常处理的初学者入门。本文后附有c++异常的知识普及
- Java 1.0 IO系统介绍1 Java IO版本Java库的IO分为输入/输出两部分。早期的Java 1.0版本的输入系统是InputS
- 本文以实例形式展示了C#判等对象是否相等的常用方法,非常实用,可供大家参考借鉴之用。具体分析如下:一、判断相等的3个方法1.实例方法publ