一、引言
在 Spring Boot 开发中,Redis 凭借其高性能和丰富的数据结构,成为缓存、分布式锁、消息队列等场景的首选解决方案。为了提升开发效率,避免重复配置和代码编写,我们可以创建一个自定义的 Redis Starter。本文将详细介绍如何在 IDEA 中创建一个功能强大的自定义 Redis Starter,包括项目搭建、代码实现、功能扩展以及配置文件的编写。
二、在 IDEA 中创建项目步骤
2.1 新建项目
打开 IntelliJ IDEA,选择 File -> New -> Project,在弹出的窗口中选择 Maven,确保 JDK 版本正确,然后点击 Next。
2.2 填写项目信息
输入 GroupId、ArtifactId 和 Version 等项目信息,这里我们填写 com.selfmade、selfmade-redis-starter 和 1.0.0,然后点击 Next。
2.3 选择项目位置
选择项目的存储位置,点击 Finish 完成项目创建。
2.4 项目结构
创建完成后,项目的基本结构如下:
selfmade-redis-starter
├── src
│ ├── main
│ │ ├── java
│ │ └── resources
│ │ └── META-INF
│ └── test
│ ├── java
│ └── resources
└── pom.xml
三、项目依赖配置(pom.xml)
4.0.0
com.selfmade
selfmade-redis-starter
1.0.0
jar
Self-made Redis Starter
A custom Redis starter for Spring Boot applications with enhanced features
org.springframework.boot
spring-boot-autoconfigure
org.springframework.boot
spring-boot-starter-cache
org.springframework.boot
spring-boot-starter-data-redis
com.fasterxml.jackson.core
jackson-databind
cn.hutool
hutool-all
5.8.10
org.apache.maven.plugins
maven-jar-plugin
3.2.2
true
lib/
四、核心代码实现
4.1 自定义 Redis 缓存类 `EnhancedRedisCache.java`
package com.selfmade.autoconfigure.redis;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import java.util.Set;
// 自定义 Redis 缓存类,继承自 RedisCache
public class EnhancedRedisCache extends RedisCache {
// 定义通配符,用于匹配多个键
private static final String MULTI_KEY_MATCH = "*";
// Redis 连接工厂,用于获取 Redis 连接
private final RedisConnectionFactory redisConnectFactory;
/**
* 构造函数,初始化自定义 Redis 缓存对象
* @param cacheName 缓存名称
* @param cacheWriter Redis 缓存写入器
* @param cacheConfig Redis 缓存配置
* @param connectFactory Redis 连接工厂
*/
public EnhancedRedisCache(String cacheName, RedisCacheWriter cacheWriter, RedisCacheConfiguration cacheConfig, RedisConnectionFactory connectFactory) {
super(cacheName, cacheWriter, cacheConfig);
this.redisConnectFactory = connectFactory;
}
/**
* 重写 evict 方法,支持通配符删除缓存
* @param cacheKey 要删除的缓存键
*/
@Override
public void evict(Object cacheKey) {
if (cacheKey instanceof String) {
String keyStr = (String) cacheKey;
if (keyStr.contains(MULTI_KEY_MATCH)) {
// 生成完整的缓存键
String fullCacheKeyPattern = super.createCacheKey(keyStr);
// 执行通配符删除操作
deleteKeysByPattern(fullCacheKeyPattern);
return;
}
}
// 普通键删除操作,调用父类方法
super.evict(cacheKey);
}
/**
* 根据通配符模式删除缓存键
* @param pattern 通配符模式
*/
private void deleteKeysByPattern(String pattern) {
try (RedisConnection connection = redisConnectFactory.getConnection()) {
// 获取匹配的所有键
Set matchedKeys = connection.keys(pattern.getBytes());
if (matchedKeys != null && !matchedKeys.isEmpty()) {
// 删除匹配的键
connection.del(matchedKeys.toArray(new byte[0][]));
}
}
}
}
4.2 Redis 自动配置类 RedisAutoConfig.java
package com.selfmade.autoconfigure.redis;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
// 标记为配置类
@Configuration
// 在 Redis 自动配置之后进行配置
@AutoConfigureAfter(RedisAutoConfiguration.class)
// 启用 Spring 缓存功能
@EnableCaching
public class RedisAutoConfig {
/**
* 自定义 RedisTemplate Bean
* @param redisConnectFactory Redis 连接工厂
* @return 自定义的 RedisTemplate
*/
@Bean
@ConditionalOnClass(RedisTemplate.class)
public RedisTemplate customRedisTemplate(RedisConnectionFactory redisConnectFactory) {
// 创建 RedisTemplate 实例
RedisTemplate redisTemplate = new RedisTemplate<>();
// 设置 Redis 连接工厂
redisTemplate.setConnectionFactory(redisConnectFactory);
// 创建 Jackson2JsonRedisSerializer 用于值的序列化
Jackson2JsonRedisSerializer<Object> jsonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
// 设置对象的所有属性都可访问
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 开启默认类型信息,方便反序列化
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
jsonSerializer.setObjectMapper(objectMapper);
// 创建 StringRedisSerializer 用于键的序列化
StringRedisSerializer stringSerializer = new StringRedisSerializer();
// 设置键的序列化方式
redisTemplate.setKeySerializer(stringSerializer);
// 设置哈希键的序列化方式
redisTemplate.setHashKeySerializer(stringSerializer);
// 设置值的序列化方式
redisTemplate.setValueSerializer(jsonSerializer);
// 设置哈希值的序列化方式
redisTemplate.setHashValueSerializer(jsonSerializer);
// 初始化 RedisTemplate
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
* 自定义 Redis 缓存配置 Bean
* @param redisTemplate RedisTemplate 实例
* @return Redis 缓存配置
*/
@Bean
@ConditionalOnBean(RedisTemplate.class)
public RedisCacheConfiguration customRedisCacheConfig(RedisTemplate redisTemplate) {
// 创建 StringRedisSerializer 用于键的序列化
StringRedisSerializer stringSerializer = new StringRedisSerializer();
// 获取默认的 Redis 缓存配置
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
// 设置缓存的默认过期时间为 240 分钟
.entryTtl(Duration.ofMinutes(240))
// 禁止缓存空值
.disableCachingNullValues()
// 设置键的序列化方式
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringSerializer))
// 设置值的序列化方式
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()));
return config;
}
/**
* 自定义 Redis 缓存管理器 Bean
* @param redisTemplate RedisTemplate 实例
* @param cacheConfig Redis 缓存配置实例
* @return Redis 缓存管理器
*/
@Bean
@ConditionalOnBean({RedisTemplate.class, RedisCacheConfiguration.class})
public RedisCacheManager customRedisCacheManager(RedisTemplate redisTemplate, RedisCacheConfiguration cacheConfig) {
// 获取 Redis 连接工厂
RedisConnectionFactory connectFactory = redisTemplate.getConnectionFactory();
// 创建非锁定的 Redis 缓存写入器
RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectFactory);
// 创建 Redis 缓存管理器
return new RedisCacheManager(cacheWriter, cacheConfig) {
/**
* 重写创建 Redis 缓存的方法,使用自定义的 Redis 缓存类
* @param cacheName 缓存名称
* @param config 缓存配置
* @return 自定义的 Redis 缓存实例
*/
@Override
protected RedisCache createRedisCache(String cacheName, RedisCacheConfiguration config) {
return new EnhancedRedisCache(cacheName, cacheWriter, config, connectFactory);
}
};
}
}
4.3 Redis 操作工具类 RedisOperator.java
package com.selfmade.autoconfigure.redis;
import cn.hutool.core.util.StrUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
// 标记为 Spring 组件
@Component
public class RedisOperator {
// 注入 RedisTemplate 实例
@Resource
private RedisTemplate customRedisTemplate;
// 无效键的错误信息
private static final String INVALID_KEY_ERROR = "The provided key is invalid!";
/**
* 设置缓存键的过期时间
* @param cacheKey 缓存键
* @param time 时间值
* @param timeUnit 时间单位
* @return 操作是否成功
*/
public boolean setExpiration(String cacheKey, long time, TimeUnit timeUnit) {
if (StrUtil.isEmpty(cacheKey)) {
// 记录错误日志
System.err.println(INVALID_KEY_ERROR);
return false;
}
try {
// 设置过期时间
return customRedisTemplate.expire(cacheKey, time, timeUnit);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 获取缓存键的过期时间
* @param cacheKey 缓存键
* @param timeUnit 时间单位
* @return 过期时间
*/
public Long getExpiration(String cacheKey, TimeUnit timeUnit) {
if (StrUtil.isEmpty(cacheKey)) {
// 记录错误日志
System.err.println(INVALID_KEY_ERROR);
return null;
}
try {
// 获取过期时间
return customRedisTemplate.getExpire(cacheKey, timeUnit);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 判断缓存键是否存在
* @param cacheKey 缓存键
* @return 是否存在
*/
public boolean keyExists(String cacheKey) {
if (StrUtil.isEmpty(cacheKey)) {
// 记录错误日志
System.err.println(INVALID_KEY_ERROR);
return false;
}
try {
// 判断键是否存在
return customRedisTemplate.hasKey(cacheKey);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存键
* @param cacheKey 缓存键
* @return 删除是否成功
*/
public boolean deleteKey(String cacheKey) {
if (StrUtil.isEmpty(cacheKey)) {
// 记录错误日志
System.err.println(INVALID_KEY_ERROR);
return false;
}
try {
// 删除键
return customRedisTemplate.delete(cacheKey);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除多个缓存键
* @param cacheKeys 缓存键列表
* @return 删除的键数量
*/
public Long deleteKeys(List cacheKeys) {
if (cacheKeys == null || cacheKeys.isEmpty()) {
// 记录错误日志
System.err.println(INVALID_KEY_ERROR);
return 0L;
}
try {
// 删除多个键
return customRedisTemplate.delete(cacheKeys);
} catch (Exception e) {
e.printStackTrace();
return 0L;
}
}
/**
* 获取缓存键的值
* @param cacheKey 缓存键
* @return 缓存值
*/
public Object getValue(String cacheKey) {
if (StrUtil.isEmpty(cacheKey)) {
// 记录错误日志
System.err.println(INVALID_KEY_ERROR);
return null;
}
try {
// 获取键的值
return customRedisTemplate.opsForValue().get(cacheKey);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 设置缓存键的值
* @param cacheKey 缓存键
* @param cacheValue 缓存值
* @return 操作是否成功
*/
public boolean setValue(String cacheKey, Object cacheValue) {
if (StrUtil.isEmpty(cacheKey)) {
// 记录错误日志
System.err.println(INVALID_KEY_ERROR);
return false;
}
try {
// 设置键的值
customRedisTemplate.opsForValue().set(cacheKey, cacheValue);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 设置缓存键的值并指定过期时间
* @param cacheKey 缓存键
* @param cacheValue 缓存值
* @param time 时间值
* @param timeUnit 时间单位
* @return 操作是否成功
*/
public boolean setValueWithExpiration(String cacheKey, Object cacheValue, long time, TimeUnit timeUnit) {
if (StrUtil.isEmpty(cacheKey)) {
// 记录错误日志
System.err.println(INVALID_KEY_ERROR);
return false;
}
try {
if (time > 0) {
// 设置键的值并指定过期时间
customRedisTemplate.opsForValue().set(cacheKey, cacheValue, time, timeUnit);
} else {
// 不设置过期时间
setValue(cacheKey, cacheValue);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 获取哈希表中的值
* @param hashKey 哈希表键
* @param fieldKey 哈希表中的字段键
* @return 哈希表中的值
*/
public Object hGet(String hashKey, String fieldKey) {
if (StrUtil.isEmpty(hashKey) || StrUtil.isEmpty(fieldKey)) {
// 记录错误日志
System.err.println(INVALID_KEY_ERROR);
return null;
}
try {
// 获取哈希表中的值
return customRedisTemplate.opsForHash().get(hashKey, fieldKey);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取哈希表的所有字段和值
* @param hashKey 哈希表键
* @return 哈希表的所有字段和值
*/
public Map
五、Spring Factories 配置
在 src/main/resources/META - INF 目录下创建 spring.factories 文件,该文件用于告诉 Spring Boot 自动配置类的位置。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.selfmade.autoconfigure.redis.RedisAutoConfig
六、使用说明
其他 Spring Boot 项目若要使用这个自定义的 Redis Starter,只需在 pom.xml 中添加对该 Starter 的依赖:
com.selfmade
selfmade-redis-starter
1.0.0
然后在需要使用 Redis 操作的地方注入 RedisOperator 类:
import com.selfmade.autoconfigure.redis.RedisOperator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@Autowired
private RedisOperator redisOperator;
public void doSomethingWithRedis() {
// 设置缓存值
redisOperator.setValue("myKey", "myValue");
// 获取缓存值
Object value = redisOperator.getValue("myKey");
System.out.println("Value from Redis: " + value);
// 尝试获取分布式锁
boolean locked = redisOperator.tryLock("myLock", "123456", 10, TimeUnit.SECONDS);
if (locked) {
try {
// 执行需要加锁的业务逻辑
System.out.println("Lock acquired, doing business...");
} finally {
// 释放分布式锁
redisOperator.unlock("myLock", "123456");
}
}
}
}
七、总结
本自定义 Redis Starter 通过封装 Redis 的配置和常用操作,为 Spring Boot 项目提供了便捷的 Redis 使用方式。它具有以下特点和优势:
7.1 功能丰富
提供了基本的缓存操作,如设置、获取、删除缓存键值,支持哈希表、有序集合、列表等多种数据结构的操作。
实现了分布式锁功能,可用于高并发场景下的资源互斥访问。
支持发布 - 订阅模式,方便实现消息队列和事件通知机制。
7.2 易于使用
其他 Spring Boot 项目只需添加依赖并注入 RedisOperator 类,即可轻松使用 Redis 的各项功能,无需进行复杂的配置。
7.3 可扩展性强
代码结构清晰,方便后续进行功能扩展,如添加新的 Redis 操作方法、优化分布式锁的实现等。
通过使用这个自定义 Redis Starter,开发者可以更高效地利用 Redis 的强大功能,提升项目的性能和稳定性。
本文暂时没有评论,来添加一个吧(●'◡'●)