前端开发入门到精通的在线学习网站

网站首页 > 资源文章 正文

自定义 Redis Starter 实现与扩展全解析

qiguaw 2025-03-11 20:31:10 资源文章 69 ℃ 0 评论

一、引言

在 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 hGetAll(String hashKey) {
        if (StrUtil.isEmpty(hashKey)) {
            // 记录错误日志
            System.err.println(INVALID_KEY_ERROR);
            return null;
        }
        try {
            // 获取哈希表的所有字段和值
            return customRedisTemplate.opsForHash().entries(hashKey);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
 
    /**
     * 设置哈希表中的字段和值
     * @param hashKey 哈希表键
     * @param fieldKey 哈希表中的字段键
     * @param fieldValue 哈希表中的字段值
     * @return 操作是否成功
     */
    public boolean hSet(String hashKey, String fieldKey, Object fieldValue) {
        if (StrUtil.isEmpty(hashKey) || StrUtil.isEmpty(fieldKey)) {
            // 记录错误日志
            System.err.println(INVALID_KEY_ERROR);
            return false;
        }
        try {
            // 设置哈希表中的字段和值
            customRedisTemplate.opsForHash().put(hashKey, fieldKey, fieldValue);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 设置哈希表中的多个字段和值
     * @param hashKey 哈希表键
     * @param fieldMap 包含多个字段和值的 Map
     * @return 操作是否成功
     */
    public boolean hSetAll(String hashKey, Map fieldMap) {
        if (StrUtil.isEmpty(hashKey) || fieldMap == null || fieldMap.isEmpty()) {
            // 记录错误日志
            System.err.println(INVALID_KEY_ERROR);
            return false;
        }
        try {
            // 设置哈希表中的多个字段和值
            customRedisTemplate.opsForHash().putAll(hashKey, fieldMap);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 删除哈希表中的字段
     * @param hashKey 哈希表键
     * @param fieldKeys 要删除的字段键数组
     * @return 删除的字段数量
     */
    public Long hDelete(String hashKey, Object... fieldKeys) {
        if (StrUtil.isEmpty(hashKey) || fieldKeys == null || fieldKeys.length == 0) {
            // 记录错误日志
            System.err.println(INVALID_KEY_ERROR);
            return 0L;
        }
        try {
            // 删除哈希表中的字段
            return customRedisTemplate.opsForHash().delete(hashKey, fieldKeys);
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }
 
    /**
     * 判断哈希表中是否存在指定字段
     * @param hashKey 哈希表键
     * @param fieldKey 要检查的字段键
     * @return 是否存在
     */
    public boolean hHasKey(String hashKey, String fieldKey) {
        if (StrUtil.isEmpty(hashKey) || StrUtil.isEmpty(fieldKey)) {
            // 记录错误日志
            System.err.println(INVALID_KEY_ERROR);
            return false;
        }
        try {
            // 判断哈希表中是否存在指定字段
            return customRedisTemplate.opsForHash().hasKey(hashKey, fieldKey);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 向有序集合中添加元素
     * @param zSetKey 有序集合键
     * @param value 元素值
     * @param score 元素分数
     * @return 操作是否成功
     */
    public boolean zAdd(String zSetKey, Object value, double score) {
        if (StrUtil.isEmpty(zSetKey)) {
            // 记录错误日志
            System.err.println(INVALID_KEY_ERROR);
            return false;
        }
        try {
            // 向有序集合中添加元素
            return customRedisTemplate.opsForZSet().add(zSetKey, value, score);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 获取有序集合中指定范围的元素(按分数从小到大排序)
     * @param zSetKey 有序集合键
     * @param start 起始索引
     * @param end 结束索引
     * @return 元素集合
     */
    public Set<Object> zRange(String zSetKey, long start, long end) {
        if (StrUtil.isEmpty(zSetKey)) {
            // 记录错误日志
            System.err.println(INVALID_KEY_ERROR);
            return null;
        }
        try {
            // 获取有序集合中指定范围的元素
            return customRedisTemplate.opsForZSet().range(zSetKey, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
 
    /**
     * 获取有序集合中指定范围的元素(按分数从大到小排序)
     * @param zSetKey 有序集合键
     * @param start 起始索引
     * @param end 结束索引
     * @return 元素集合
     */
    public Set<Object> zReverseRange(String zSetKey, long start, long end) {
        if (StrUtil.isEmpty(zSetKey)) {
            // 记录错误日志
            System.err.println(INVALID_KEY_ERROR);
            return null;
        }
        try {
            // 获取有序集合中指定范围的元素(按分数从大到小排序)
            return customRedisTemplate.opsForZSet().reverseRange(zSetKey, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
 
    /**
     * 获取有序集合中元素的分数
     * @param zSetKey 有序集合键
     * @param value 元素值
     * @return 元素分数
     */
    public Double zScore(String zSetKey, Object value) {
        if (StrUtil.isEmpty(zSetKey)) {
            // 记录错误日志
            System.err.println(INVALID_KEY_ERROR);
            return null;
        }
        try {
            // 获取有序集合中元素的分数
            return customRedisTemplate.opsForZSet().score(zSetKey, value);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
 
    /**
     * 从有序集合中移除元素
     * @param zSetKey 有序集合键
     * @param values 要移除的元素值数组
     * @return 移除的元素数量
     */
    public Long zRemove(String zSetKey, Object... values) {
        if (StrUtil.isEmpty(zSetKey) || values == null || values.length == 0) {
            // 记录错误日志
            System.err.println(INVALID_KEY_ERROR);
            return 0L;
        }
        try {
            // 从有序集合中移除元素
            return customRedisTemplate.opsForZSet().remove(zSetKey, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }
 
    /**
     * 向列表左侧插入元素
     * @param listKey 列表键
     * @param value 元素值
     * @return 插入元素后的列表长度
     */
    public Long lLeftPush(String listKey, Object value) {
        if (StrUtil.isEmpty(listKey)) {
            // 记录错误日志
            System.err.println(INVALID_KEY_ERROR);
            return 0L;
        }
        try {
            // 向列表左侧插入元素
            return customRedisTemplate.opsForList().leftPush(listKey, value);
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }
 
    /**
     * 从列表左侧弹出元素
     * @param listKey 列表键
     * @return 弹出的元素值
     */
    public Object lLeftPop(String listKey) {
        if (StrUtil.isEmpty(listKey)) {
            // 记录错误日志
            System.err.println(INVALID_KEY_ERROR);
            return null;
        }
        try {
            // 从列表左侧弹出元素
            return customRedisTemplate.opsForList().leftPop(listKey);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
 
    /**
     * 获取列表指定范围的元素
     * @param listKey 列表键
     * @param start 起始索引
     * @param end 结束索引
     * @return 元素列表
     */
    public List<Object> lRange(String listKey, long start, long end) {
        if (StrUtil.isEmpty(listKey)) {
            // 记录错误日志
            System.err.println(INVALID_KEY_ERROR);
            return null;
        }
        try {
            // 获取列表指定范围的元素
            return customRedisTemplate.opsForList().range(listKey, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
import java.util.concurrent.TimeUnit;
 
// 在 RedisOperator 类中添加以下方法
 
/**
 * 尝试获取分布式锁
 * @param lockKey 锁的键
 * @param requestId 请求标识,用于释放锁时验证
 * @param expireTime 锁的过期时间
 * @param timeUnit 时间单位
 * @return 是否成功获取锁
 */
public boolean tryLock(String lockKey, String requestId, long expireTime, TimeUnit timeUnit) {
    if (StrUtil.isEmpty(lockKey) || StrUtil.isEmpty(requestId)) {
        System.err.println(INVALID_KEY_ERROR);
        return false;
    }
    try {
        // 使用 Redis 的 setIfAbsent 方法尝试获取锁
        Boolean result = customRedisTemplate.opsForValue().setIfAbsent(lockKey, requestId, expireTime, timeUnit);
        return result != null && result;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}
 
/**
 * 释放分布式锁
 * @param lockKey 锁的键
 * @param requestId 请求标识,用于验证
 * @return 是否成功释放锁
 */
public boolean unlock(String lockKey, String requestId) {
    if (StrUtil.isEmpty(lockKey) || StrUtil.isEmpty(requestId)) {
        System.err.println(INVALID_KEY_ERROR);
        return false;
    }
    try {
        // 获取锁的当前值
        Object currentValue = customRedisTemplate.opsForValue().get(lockKey);
        if (currentValue != null && currentValue.toString().equals(requestId)) {
            // 验证请求标识,若匹配则删除锁
            return customRedisTemplate.delete(lockKey);
        }
        return false;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}
 
// 在 RedisOperator 类中添加以下方法
 
/**
 * 发布消息到指定频道
 * @param channel 频道名称
 * @param message 消息内容
 */
public void publishMessage(String channel, Object message) {
    if (StrUtil.isEmpty(channel)) {
        System.err.println(INVALID_KEY_ERROR);
        return;
    }
    try {
        // 使用 RedisTemplate 的 convertAndSend 方法发布消息
        customRedisTemplate.convertAndSend(channel, message);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
 
/**
 * 订阅指定频道的消息
 * @param channel 频道名称
 * @param messageListener 消息监听器
 */
public void subscribeMessage(String channel, MessageListener messageListener) {
    if (StrUtil.isEmpty(channel) || messageListener == null) {
        System.err.println(INVALID_KEY_ERROR);
        return;
    }
    try {
        // 获取 Redis 连接工厂
        RedisConnectionFactory connectFactory = customRedisTemplate.getConnectionFactory();
        if (connectFactory != null) {
            // 创建 Redis 消息监听容器
            RedisMessageListenerContainer container = new RedisMessageListenerContainer();
            container.setConnectionFactory(connectFactory);
            // 向容器中添加监听器和频道
            container.addMessageListener(messageListener, new PatternTopic(channel));
            // 启动容器
            container.start();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

五、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 的强大功能,提升项目的性能和稳定性。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表