0


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

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等系列文章,一系列干货随时送达!

标签: redis spring boot java

本文转载自: https://blog.csdn.net/jinxinxin1314/article/details/130676228
版权归原作者 fking86 所有, 如有侵权,请联系我们删除。

“【Springboot系列】整合redis+jedis(含源码)”的评论:

还没有评论