【Springboot系列】整合redis+jedis(含源码)

news/2024/7/3 1:37:32

Spring Boot集成Redis和Jedis客户端使用Redis有以下主要特点:

​ 👉简单易用只需要添加相关依赖和简单配置,就可以直接在Spring Boot应用中使用Jedis客户端操作Redis。这大大简化了使用Redis的难度。

​ 👉自动配置Spring Boot会根据类路径中的Jedis版本自动配置JedisConnectionFactory。我们只需要注入JedisConnectionFactory即可获取Jedis客户端实例。

​ 👉功能丰富通过Jedis或者Lettuce客户端,我们可以使用Redis的全部功能,如字符串、列表、集合、排序集合、哈希等数据结构,以及事务、管道等功能。

​ 👉高扩展性我们可以很容易切换不同的Redis客户端,如Jedis、Lettuce。也可以根据需要自定义RedisTemplate或添加RedisCacheManager等来改变缓存行为。

​ 👉与Spring Cache集成Spring Boot将Redis Cache Manager与Spring Cache深度集成,我们可以直接使用Spring Cache注解来注解方法和类,实现缓存功能,而不用直接依赖Redis API。

​ 👉与Spring Data Redis集成Spring Data Redis在Jedis和Lettuce基础上提供了更高级的抽象,我们可以调用其Repository接口来操作Redis,这提供了类似JPA的编程体验。

​ 👉多种缓存支持Spring Boot默认集成了多种缓存技术,如Redis、Ehcache、Hazelcast等。我们只需要一行配置即可切换缓存技术,不需要更改业务逻辑代码。

​ 👉健康监控Spring Boot Actuator可以监控RedisConnectionFactory中的连接池状态、等待连接的线程数等信息,方便我们监控Redis的运行状况。

下面我们从以下几个步骤来应用Jedis:

🌵依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.6</version>
</parent>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

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

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>2.0.22</version>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
    <optional>true</optional>
</dependency>

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>

🌵配置文件:

server:
  port: 8080  # 设置访问端口

spring:
  redis:
    enable: true
    jedis:
      host: localhost
      port: 6379
      password: 123456
      database: 0
      maxIdle: 100
      minIdle: 0
      maxTotal: 100
      maxWaitMillis: 500
      testOnBorrow: false
      testOnReturn: true

🌵RedisTestController

@RestController
@RequestMapping("/redis")
public class RedisTestController {

    @Autowired
    RedisComponent redisComponent;

    @ResponseBody
    @GetMapping("/test")
    public String test(){
        String val = "aa";
        String key = "testRedisKey";
        redisComponent.set(key, val);
        String retVal = redisComponent.get(key);
        return retVal;
    }
}

🌵JedisConfig

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

@Slf4j
@Configuration
public class JedisConfig {

    @Value("${spring.redis.jedis.host}")
    private String redisHost;

    @Value("${spring.redis.jedis.port}")
    private Integer redisPort;

    @Value("${spring.redis.jedis.password}")
    private String redisPassword;

    @Value("${spring.redis.jedis.database}")
    private Integer database;

    @Value("${spring.redis.jedis.maxIdle}")
    private Integer maxIdle;

    @Value("${spring.redis.jedis.minIdle}")
    private Integer minIde;

    @Value("${spring.redis.jedis.maxTotal}")
    private Integer maxTotal;

    @Value("${spring.redis.jedis.maxWaitMillis}")
    private Long maxWaitMillis;

    @Value("${spring.redis.jedis.testOnBorrow}")
    private Boolean testOnBorrow;

    @Value("${spring.redis.jedis.testOnReturn}")
    private Boolean testOnReturn;


    @Bean
    public JedisPool jedisPool(){
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMinIdle(minIde);
        jedisPoolConfig.setMaxTotal(maxTotal);
        jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
        jedisPoolConfig.setTestOnBorrow(testOnBorrow);
        jedisPoolConfig.setTestOnReturn(testOnReturn);

        log.info("redis properties {}, jedisPoolConfig={}" ,  this.toString(),JSONObject.toJSONString(jedisPoolConfig));
        JedisPool jedisPool = new JedisPool(jedisPoolConfig, redisHost, redisPort,0, redisPassword, database);
        return jedisPool;
    }

    @Override
    public String toString() {
        return "JedisConfig{" +
                "redisHost='" + redisHost + '\'' +
                ", redisPort=" + redisPort +
                ", redisPassword='" + redisPassword + '\'' +
                ", database=" + database +
                '}';
    }
}

🌵RedisComponent (Redis工具类)

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.Tuple;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * Created   on 2019/8/19.
 */

@Slf4j
// 是否开启redis
@ConditionalOnProperty(prefix = "spring", name = "redis.enable", havingValue = "true")
@Component
public class RedisComponent {

    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    private static final Long RELEASE_SUCCESS = 1L;
    private static final Long retryMill = 1000 * 1000 * 1L;

    @Autowired
    private JedisPool jedisPool;

    /**
     * 获取分布式锁
     *
     * @param lockKey
     * @param requestId
     * @param expireTime 毫秒
     */
    public Boolean tryDistributedLock(String lockKey, String requestId, int expireTime) {
        log.info("tryGetDistributedLock-->>lockKey = {}, requestId = {}, expireTime = {}", lockKey, requestId, expireTime);
        String result = this.setNxxxExpx(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
        log.info("tryGetDistributedLock-->>lockKey = {}, requestId = {}, result = {}", lockKey, requestId, result);
        return LOCK_SUCCESS.equals(result);
    }

    /**
     * @param lockKey       上锁的key
     * @param expireTime    锁的超时时间
     * @param retryTimeNano 最多尝试多久 纳秒单位
     * @return
     * @throws InterruptedException
     */
    public String lock(String lockKey, int expireTime, long retryTimeNano) {
        int rt = 0;
        String key = null;
        try {
            while (true) {
                key = String.valueOf(System.nanoTime());
                String result = this.setNxxxExpx(lockKey, key, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
                if (LOCK_SUCCESS.equals(result)) {
                    return key;
                }
                // 获取锁失败

                rt += retryMill;//每隔1 ms执行一次
                if (rt <= retryTimeNano) { // 下次可以执行
                    Thread.sleep(retryMill);
                } else {
                    return  null;
                }
            }
        } catch (InterruptedException e) {
            return null;
        }

    }


    /**
     * 释放分布式锁
     *
     * @param lockKey   锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public boolean releaseDistributedLock(String lockKey, String requestId) {
        log.info("releaseDistributedLock-->>, lockKey = {}, requestId = {}", lockKey, requestId);
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = this.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
        log.info("releaseDistributedLock, lockKey = {}, requestId = {}, result = {}", lockKey, requestId, result);
        if (RELEASE_SUCCESS.equals(result)) {
            log.info("releaselock>>>>>>>>>>>>>>>> lockKey = {}, requestId = {}", lockKey, requestId);
            return true;
        }
        log.info("锁已释放, lockKey = {}, requestId = {}", lockKey, requestId);
        return false;

    }


    public final <OUT> OUT redisExec(Function<Jedis, OUT> function) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return function.apply(jedis);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("redisExec error, errorMsg = {}", e.getMessage());
            throw e;
        } finally {
            Optional.ofNullable(jedis).ifPresent(j -> j.close());
        }
    }


    public String setNxxxExpx(final String key, final String value, final String nxxx, final String expx,
                              final int time) {
        return redisExec(jedis -> jedis.set(key, value, nxxx, expx, time));
    }

    public Object eval(String script, List<String> keys, List<String> args) {
        return redisExec(jedis -> jedis.eval(script, keys, args));
    }

    public String get(String key) {
        return this.redisExec(redis -> redis.get(key));
    }

    public byte[] getBytes(byte[] key) {
        return this.redisExec(redis -> redis.get(key));
    }

    public void set(String key, String val) {
        this.redisExec(redis -> redis.set(key, val));
    }

    public Long incr(String key) {
        return this.redisExec(redis -> redis.incr(key));
    }

    public Long append(String key, String value) {
        return this.redisExec(redis->redis.append(key, value));
    }
    public void set(String key, String val, int expireSecond) {
        this.redisTxExec(tx -> {
            tx.set(key, val);
            tx.expire(key, expireSecond);
        });
    }

    public Long rpush(String key, String val) {
        return this.redisExec(tx-> tx.rpush(key, val));
    }

    public String lpop(String key) {
        return this.redisExec(tx->tx.lpop(key));
    }

    public void setBytes(byte[] key, byte[] val, int expireSecond) {
        this.redisTxExec(tx -> {
            tx.set(key, val);
            tx.expire(key, expireSecond);
        });
    }

    public Long SAdd(String key, final String... field) {
        return this.redisExec((redis -> redis.sadd(key, field)));
    }

    public Long ZAdd(String key, double score, String mem) {
        return this.redisExec((redis -> redis.zadd(key, score, mem)));
    }

    public Long SRem(String key, final String... field) {
        return this.redisExec((redis -> redis.srem(key, field)));
    }


    public Long IncBy(String key, Long val) {
        return this.redisExec((redis -> redis.incrBy(key, val)));
    }

    public Long del(String key) {
        return this.redisExec(redis -> redis.del(key));
    }

    public Long del(byte[] key) {
        return this.redisExec(redis -> redis.del(key));
    }

    public Long delByte(byte[] key) {
        return this.redisExec(redis -> redis.del(key));
    }

    public Long hdel(String key, String fileds) {
        return this.redisExec(redis -> redis.hdel(key, fileds));
    }

    public Boolean exists(String key) {
        return this.redisExec(redis -> redis.exists(key));
    }

    public Long scard(String key) {
        return this.redisExec(redis -> redis.scard(key));
    }

    public String srandmember(String key) {
        return this.redisExec(redis -> redis.srandmember(key));
    }

    public Set<String> smembers(String key) {
        return this.redisExec(redis -> redis.smembers(key));
    }

    public boolean sismember(String key, String value) {
        return this.redisExec(redis -> redis.sismember(key, value));
    }

    public Boolean hexists(String key, String ele) {
        return this.redisExec(redis -> redis.hexists(key, ele));
    }

    public String hget(String key, String filed) {
        return this.redisExec(redis -> redis.hget(key, filed));
    }

    public Map<String, String> hgetall(String key) {
        return redisExec(redis -> redis.hgetAll(key));
    }

    public Set<String> zrange(String key, Long start, Long end) {
        return this.redisExec(redis -> redis.zrange(key, start, end));
    }


    public Long zadd(String key, double score, String member) {
        return this.redisExec(redis->redis.zadd(key, score, member));
    }

    public Long zrem(String key, String... mem) {
        return this.redisExec(r -> r.zrem(key, mem));
    }

    public Set<String> zrevrange(String key, Long start, Long end) {
        return this.redisExec(redis -> redis.zrevrange(key, start, end));
    }

    public Set<Tuple> zrevrangeWithScores(String key, Long start, Long end) {
        return this.redisExec(redis -> redis.zrevrangeWithScores(key, start, end));
    }


    public Set<Tuple> zrangeWithScores(String key, Long start, Long end) {
        return this.redisExec(redis -> redis.zrangeWithScores(key, start, end));
    }

    public Long zrank(String key, String member) {
        return this.redisExec(redis -> redis.zrank(key, member));
    }

    public Set<String> hkeys(String key) {
        return this.redisExec(redis -> redis.hkeys(key));
    }

    public List<String> lrange(String key, Long start, Long end) {
        return this.redisExec(redis -> redis.lrange(key, start, end));
    }

    public Long expire(String key, int expireSecond) {
        return this.redisExec(redis -> redis.expire(key, expireSecond));
    }

    public Long TTL(String key) {
        return this.redisExec(redis -> redis.ttl(key));
    }


    public void redisTxExec(Consumer<Transaction> consumer) {
        List<Object> result = this.redisExec(jedis -> {
            Transaction tx = jedis.multi();
            consumer.accept(tx);
            return tx.exec();
        });
    }

    public void redisWatchTxExec(Consumer<Transaction> consumer, String... args) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.watch(args);
            Transaction tx = jedis.multi();
            consumer.accept(tx);
            List<Object> execResult = tx.exec();
            log.info("jedis tx result = {}", execResult);
            if (CollectionUtils.isEmpty(execResult)) {
               return;
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info("redisExec error, errorMsg = {}", e.getMessage());
            throw e;
        } finally {
            Optional.ofNullable(jedis).ifPresent(j -> j.close());
        }
    }
}

简而言之,Spring Boot与Redis和Jedis的深度集成,让Redis变得异常易用和高效。凭借Spring Boot的“自动配置、起步依赖、产生型API”等特性,我们可以快速上手Redis,开发基于Redis的应用,从而享受Redis强大的功能。这大大提高了开发效率和项目的重用性。

掌握Spring Boot与Redis的集成技术,对我们成为一名专业的后端开发者来说是非常有必要的。这是一项值得长期研究与实践的技能。

🎁如果需要完整源码请关注公众号"架构殿堂" ,回复 "redis+jedis"即可获得

🔔写在最后

如果大家对相关文章感兴趣,可以关注公众号"架构殿堂",会持续更新AIGC,java基础面试题, netty, spring boot,spring cloud等系列文章,一系列干货随时送达!


http://lihuaxi.xjx100.cn/news/1133188.html

相关文章

OPPO舍弃芯片研发,让人想起欧洲芯片,国产芯片会从此溃败么?

OPPO一瞬间舍弃芯片研发&#xff0c;对国产芯片造成的影响无疑是非常大的&#xff0c;甚至可能导致国产芯片的研发由此溃败&#xff0c;这可以从当年欧洲的芯片业务衰败作为前车之鉴。 GSM称霸2G时代&#xff0c;也让欧洲手机和欧洲芯片企业取得优势&#xff0c;当年爱立信手机…

30从零开始学Java之详解面向对象的7种创建方式

作者&#xff1a;孙玉昌&#xff0c;昵称【一一哥】&#xff0c;另外【壹壹哥】也是我哦 千锋教育高级教研员、CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者 前言 在上一篇文章中&#xff0c;壹哥给大家介绍了Java中的类及其特点、创建过程等内容&#xff0c;相信你…

基于python计算生态的第三方库总结与介绍

摘要&#xff1a;Python语言有超过12万个第三方库&#xff0c;覆盖信息技术几乎所有领域。即使在每个方向&#xff0c;也会有大量的专业人员开发多个第三方库来给出具体设计。正是因为python有了这么多“隐形的翅膀”&#xff0c;所以python的功能才足够庞大。本文主要针对pyth…

Linux安装使用PostgreSQL

安装PostgreSQL 开源数据库&#xff1a;PostgreSQL 在官网选择对应版本的安装包 https://www.postgresql.org/download/ 我的Linux系统是CentOS7 选择对应的系统 选择安装的版本、平台、架构 复制粘贴安装脚本运行 初始化后会创建一个用户postgres&#xff0c;一般开始…

asm 加盘 udev 重启 导致网络异常

Network interface going down when dynamically adding disks to storage using udev in RHEL 6 (Doc ID 1569028.1)正在上传…重新上传取消To Bottom In this Document APPLIES TO: Oracle Database - Enterprise Edition - Version 11.2.0.3 and later Oracle Net Servi…

iPhone照片导入电脑的图文教程,批量上传的3个方法!

案例&#xff1a;苹果手机照片怎么批量上传到电脑&#xff1f; 【友友们&#xff0c;手机照片太多&#xff0c;占用了我很多内存。想要把照片上传批量上传到电脑上进行保存&#xff0c;该怎么做&#xff1f;】 随着iPhone的普及和摄影功能的提升&#xff0c;越来越多的用户希望…

排列熵及其matlab实现方法

排列熵是信息论中的一个重要概念&#xff0c;用于衡量系统的复杂度和随机性。在实际应用中&#xff0c;排列熵被广泛应用于信号处理、图像处理、生物信息学、金融经济学等领域。本文将就排列熵的定义、计算方法及其在Matlab中的实现进行介绍。 一、排列熵的定义 排列熵是指在…