Spring整合Redis
前言
在Spring项目中整合Redis,能显著提升数据缓存、分布式锁、会话管理等操作的效率。Jedis作为轻量级的Java Redis客户端,搭配Spring Data Redis模块,能够简化Redis的连接和数据操作,实现更高性能的读写与灵活的缓存管理。本文将简要介绍如何在Spring中集成Jedis,配置连接池、数据序列化等内容,并通过封装工具类来优化Redis的使用体验。
[!NOTE]
Spring版本:5.3.27
JDK版本:1.8
本文基于Jedis在Spring中整合Redis
一、redis客户端分类
1.1客户端对比
特性 | Jedis | Lettuce | Redisson |
---|---|---|---|
线程安全 | × | √ | √ |
支持集群 | √ | √ | √ |
支持哨兵 | √ | √ | √ |
支持发布/订阅 | √ | √ | √ |
支持管道 | √ | √ | √ |
支持异步操作 | × | √ | √ |
支持响应式编程 | × | √ | √ |
API直观性 | √(API简单易用) | ×(API较复杂) | ×(API较复杂,丰富的功能) |
社区支持 | √ | √ | √ |
性能 | 性能较低(同步阻塞) | 高性能(异步非阻塞) | 高性能(异步非阻塞) |
资源消耗 | 较高(频繁创建连接) | 较低(连接复用) | 较低(连接复用) |
高级功能支持 | × | × | √(支持分布式锁、布隆过滤器等) |
易用性 | 高(简单易用) | 中等(需要更多配置) | 高(封装良好,功能丰富) |
学习曲线 | 低 | 中等 | 陡峭(功能丰富,学习成本高) |
文档完善度 | √ | √ | √ |
客户端实例创建 | 简单 | 较复杂(需要配置) | 较复杂(需要配置) |
连接池支持 | 需要外部支持(如Apache Commons Pool) | 内置连接池 | 内置连接池 |
跨语言支持 | × | × | × |
商业支持 | 有社区版本支持 | 有社区版本支持 | 有社区版本支持,有商业支持 |
1.2客户端简要说明
Jedis:传统的Redis客户端,基于同步阻塞模型,不支持异步操作,在高并发场景下性能受限。使用起来比较简单,API直观,适合轻量级应用和快速开发。
Lettuce:基于Netty实现的异步非阻塞客户端,支持异步、响应式编程,性能较高,尤其适用于高并发应用。需要一些额外的配置,相较于Jedis,学习曲线略陡。
Redisson:功能最为丰富,除了基本的Redis操作外,还封装了分布式锁、布隆过滤器等高级功能,适合大型、分布式应用。其API相对复杂,学习成本较高,但提供了较强的扩展性和便捷的高级特性支持。
二、依赖项
2.1依赖项说明
spring-data-redis:
- 这是Spring Data Redis模块的核心依赖,提供了对Redis的支持,简化Redis操作。
- 封装了对Redis的连接、数据访问以及常用操作的API(如
RedisTemplate
、StringRedisTemplate
),并且兼容多种Redis客户端,包括Jedis和Lettuce。 - 通过它可以轻松实现与Redis的交互,并支持连接池管理、事务支持和缓存抽象等功能。
jedis:
- Jedis是一个轻量级的Java Redis客户端,用于直接操作Redis。
spring-data-redis
虽然提供了对Redis操作的抽象,但并不包含Redis客户端,因此需要Jedis作为Redis的具体实现。- Jedis提供了同步的、简单易用的API,使得与Redis交互更加便捷。
- 在
RedisConnectionFactory
中可以配置Jedis作为连接池,为RedisTemplate
提供连接。
jackson-databind:
- Jackson是Java中的一种常用JSON处理工具库,
jackson-databind
依赖提供了将Java对象和JSON之间互相序列化和反序列化的功能。 - 在Redis中通常需要将复杂数据结构序列化为JSON格式存储,Jackson能够帮助实现对象到JSON的转换,特别适用于
RedisTemplate
的GenericJackson2JsonRedisSerializer
。 jackson-databind
结合RedisTemplate
使用,可以方便地将Java对象转换成JSON格式存储到Redis中,以及从Redis中取出JSON字符串时将其反序列化为Java对象。
2.2pom文件
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.6.10</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.4</version>
</dependency>
三、配置文件
- host:redis服务地址
- port:redis服务端口(默认6379)
- password:密码(如果设置了)
- timeout:处理客户端请求超时时间
- pool.max-total:连接池最大连接数(包括空闲连接和正在使用的连接。当连接池中的连接数量达到
maxTotal
时,如果有新的请求想要连接,连接池将会等待,直到有连接被释放为止) - pool.max-idle:连接池最大空闲连接数(当连接池中空闲连接的数量超过
maxIdle
所设置的值时,连接池会尽量释放多余的连接。这样可以避免资源的浪费,确保系统的性能和稳定性。) - pool.min-idle:连接池最小空闲连接数
redis.host=*.*.*.*
redis.port=6379
redis.password=123456
redis.timeout=60000
redis.pool.max-total=8
redis.pool.max-idle=8
redis.pool.min-idle=0
3.1配置类
3.1.1配置类说明
-
客户端及连接池配置属性使用@Value注入
-
定义了两个Spring管理的bean,分别是redisConnectionFactory和redisTemplate。
-
redisConnectionFactory用于创建和配置
RedisConnectionFactory
实例,以便为应用程序提供与Redis数据库的连接。
3.1.2redisConnectionFactory
Redis服务器地址配置:
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(host, port);
config.setPassword(password);
RedisStandaloneConfiguration
用于指定Redis的主机地址(host
)和端口(port
)。确保应用程序可以正确地连接到指定的Redis服务器。- 如果Redis设置了密码保护,
config.setPassword(password)
配置会将连接密码添加到连接配置中,以实现安全连接。
Jedis连接池配置:
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(maxTotal);
poolConfig.setMaxIdle(maxIdle);
poolConfig.setMinIdle(minIdle);
用于设置连接池的参数,以优化Redis连接的性能:
setMaxTotal(maxTotal)
:设置最大连接数,以确保高并发访问时,系统能承受足够的连接。setMaxIdle(maxIdle)
:设置连接池中的最大空闲连接数。闲置的连接可以快速被重用,减少重新创建连接的开销。setMinIdle(minIdle)
:设置连接池中的最小空闲连接数,以便在连接池变空时保留一些空闲连接,保障连接的可用性。
Jedis客户端配置:
JedisClientConfiguration clientConfig = JedisClientConfiguration.builder()
.usePooling()
.poolConfig(poolConfig)
.and()
.readTimeout(java.time.Duration.ofMillis(timeout))
.build();
配置了Jedis客户端的特定设置:
.usePooling()
启用连接池,提升资源管理效率。.poolConfig(poolConfig)
将先前设置的poolConfig
应用于Jedis的连接池。.readTimeout(java.time.Duration.ofMillis(timeout))
设置了Redis的读取超时时间,确保应用程序在与Redis通信时不会因等待过久而阻塞。
小结
创建一个配置完善的RedisConnectionFactory
实例,它将连接信息、连接池、客户端参数等封装起来,便于整个应用与Redis交互时高效、安全地使用连接池,提高资源利用率,保障Redis服务的稳定性。
3.1.3redisTemplate
创建RedisTemplate实例并配置连接工厂:
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
RedisTemplate<String, Object>
:定义了键为String
类型、值为Object
类型的模板实例,可以灵活存储任意Java对象。template.setConnectionFactory(redisConnectionFactory)
:将RedisConnectionFactory
注入RedisTemplate
,使其具备与Redis服务器通信的能力。通过该连接工厂,RedisTemplate
可以根据配置好的连接池、连接地址和超时设置来访问Redis。
配置键的序列化方式:
template.setKeySerializer(new StringRedisSerializer());
setKeySerializer(new StringRedisSerializer())
:将键的序列化方式设为StringRedisSerializer
,确保键以字符串形式存储在Redis中。字符串序列化通常便于调试和维护,适合大多数场景。
配置值的序列化方式:
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
setValueSerializer(new GenericJackson2JsonRedisSerializer())
:设置值的序列化方式为GenericJackson2JsonRedisSerializer
,该序列化器将Java对象序列化为JSON格式。这样可以直观地将复杂对象序列化为JSON字符串,便于存储和读取。JSON格式也能在不同语言中通用,提高了数据的可读性和可移植性。
配置哈希类型键值对的序列化方式:
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
setHashKeySerializer
和setHashValueSerializer
分别为哈希类型键和值指定序列化方式。Redis支持哈希结构(类似于字典),其中HashKey
用于指定字段,HashValue
用于指定字段的值。StringRedisSerializer
使得哈希键可以更易读地以字符串形式存储。GenericJackson2JsonRedisSerializer
使得哈希值也可以存储为JSON格式的字符串,适合复杂数据类型。
小结
- 便捷的Redis操作接口:封装了操作Redis常用方法,如
opsForValue()
(字符串操作)、opsForHash()
(哈希操作)等,使得代码逻辑更加清晰。 - 序列化配置增强兼容性:
RedisTemplate
支持灵活的序列化设置,使得Redis可以存储任意Java对象而不失去可读性。 - 集中管理Redis连接:通过注入的
RedisConnectionFactory
,RedisTemplate
能够高效、可靠地管理连接池,提高Redis交互效率。
3.1.4完整配置类
package com.lazy.snail.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
/**
* @ClassName RedisConfig
* @Description TODO
* @Author lazysnail
* @Date 2024/11/11 15:07
* @Version 1.0
*/
@Configuration
public class RedisConfig {
@Value("${redis.host}")
private String host;
@Value("${redis.port}")
private int port;
@Value("${redis.password}")
private String password;
@Value("${redis.timeout}")
private int timeout;
@Value("${redis.pool.max-total}")
private int maxTotal;
@Value("${redis.pool.max-idle}")
private int maxIdle;
@Value("${redis.pool.min-idle}")
private int minIdle;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
// 配置Redis服务器地址
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(host, port);
config.setPassword(password);
// 配置Jedis连接池
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(maxTotal);
poolConfig.setMaxIdle(maxIdle);
poolConfig.setMinIdle(minIdle);
JedisClientConfiguration clientConfig = JedisClientConfiguration.builder()
.usePooling()
.poolConfig(poolConfig)
.and()
.readTimeout(java.time.Duration.ofMillis(timeout))
.build();
return new JedisConnectionFactory(config, clientConfig);
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
// 设置key的序列化方式
template.setKeySerializer(new StringRedisSerializer());
// 设置value的序列化方式
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
}
四、redis工具类
4.1工具类作用
-
封装通用操作,简化调用:
RedisUtil
将Redis的常用操作方法(如set
、get
、delete
等)进行封装,简化了调用逻辑。无需直接操作RedisTemplate
的API,而是通过工具类的方法进行更直观的操作。例如,set
方法统一了过期时间的设置,get
方法直接获取值,代码更加清晰易读。 -
提升代码复用性:在项目中,操作Redis的代码可能会散布在各个业务模块中。通过
RedisUtil
工具类,将Redis操作集中管理,可以避免重复的代码,提升复用性,并且在需要更改Redis操作时,只需修改工具类即可,维护性更强。 -
方便扩展和管理:通过工具类,可以轻松扩展更多的Redis操作方法,如设置集合、哈希、列表等数据结构的操作。如果需要增加更多的Redis配置(如不同的序列化方式),也可以通过工具类实现集中管理。
-
增强代码可读性:直接调用
RedisTemplate
的API会显得代码复杂和难以理解。使用RedisUtil
的封装方法后,操作描述更直观,有助于增强代码的可读性,更容易理解Redis的操作逻辑。 -
便于统一异常处理和业务逻辑封装:工具类可以将一些异常捕获逻辑集中在一起进行处理。例如,如果Redis连接超时,可以在工具类中进行处理,避免各个模块中都添加重复的异常捕获代码,统一了异常处理的逻辑。
4.2工具类代码
package com.lazy.snail.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* @ClassName RedisUtil
* @Description TODO
* @Author lazysnail
* @Date 2024/11/11 16:47
* @Version 1.0
*/
@Component
public class RedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void set(String key, Object value, long timeout) {
redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
}
public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
public boolean delete(String key) {
return Boolean.TRUE.equals(redisTemplate.delete(key));
}
public boolean hasKey(String key) {
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
}
public boolean expire(String key, long timeout) {
return Boolean.TRUE.equals(redisTemplate.expire(key, timeout, TimeUnit.SECONDS));
}
}
五、测试类
5.1测试类代码
package com.lazy.snail;
import com.lazy.snail.config.AppConfig;
import com.lazy.snail.util.RedisUtil;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = AppConfig.class)
@TestPropertySource("classpath:application.properties")
public class SpringTest {
@Autowired
private RedisUtil redisUtil;
@Test
void test() {
redisUtil.set("test", "test", 60);
redisUtil.delete("test");
}
}
5.2测试结果:
原文地址:https://blog.csdn.net/indolentSnail/article/details/143713127
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!