Spring Boot集成Redis和Jedis客戶端使用Redis有以下主要特點(diǎn):
? ??簡(jiǎn)單易用只需要添加相關(guān)依賴和簡(jiǎn)單配置,就可以直接在Spring Boot應(yīng)用中使用Jedis客戶端操作Redis。這大大簡(jiǎn)化了使用Redis的難度。
? ??自動(dòng)配置Spring Boot會(huì)根據(jù)類路徑中的Jedis版本自動(dòng)配置JedisConnectionFactory。我們只需要注入JedisConnectionFactory即可獲取Jedis客戶端實(shí)例。
? ??功能豐富通過Jedis或者Lettuce客戶端,我們可以使用Redis的全部功能,如字符串、列表、集合、排序集合、哈希等數(shù)據(jù)結(jié)構(gòu),以及事務(wù)、管道等功能。
? ??高擴(kuò)展性我們可以很容易切換不同的Redis客戶端,如Jedis、Lettuce。也可以根據(jù)需要自定義RedisTemplate或添加RedisCacheManager等來改變緩存行為。
? ??與Spring Cache集成Spring Boot將Redis Cache Manager與Spring Cache深度集成,我們可以直接使用Spring Cache注解來注解方法和類,實(shí)現(xiàn)緩存功能,而不用直接依賴Redis API。
? ??與Spring Data Redis集成Spring Data Redis在Jedis和Lettuce基礎(chǔ)上提供了更高級(jí)的抽象,我們可以調(diào)用其Repository接口來操作Redis,這提供了類似JPA的編程體驗(yàn)。
? ??多種緩存支持Spring Boot默認(rèn)集成了多種緩存技術(shù),如Redis、Ehcache、Hazelcast等。我們只需要一行配置即可切換緩存技術(shù),不需要更改業(yè)務(wù)邏輯代碼。
? ??健康監(jiān)控Spring Boot Actuator可以監(jiān)控RedisConnectionFactory中的連接池狀態(tài)、等待連接的線程數(shù)等信息,方便我們監(jiān)控Redis的運(yùn)行狀況。
下面我們從以下幾個(gè)步驟來應(yīng)用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 # 設(shè)置訪問端口
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 鎖的超時(shí)時(shí)間
* @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執(zhí)行一次
if (rt <= retryTimeNano) { // 下次可以執(zhí)行
Thread.sleep(retryMill);
} else {
return null;
}
}
} catch (InterruptedException e) {
return null;
}
}
/**
* 釋放分布式鎖
*
* @param lockKey 鎖
* @param requestId 請(qǐng)求標(biāo)識(shí)
* @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());
}
}
}
簡(jiǎn)而言之,Spring Boot與Redis和Jedis的深度集成,讓Redis變得異常易用和高效。憑借Spring Boot的“自動(dòng)配置、起步依賴、產(chǎn)生型API”等特性,我們可以快速上手Redis,開發(fā)基于Redis的應(yīng)用,從而享受Redis強(qiáng)大的功能。這大大提高了開發(fā)效率和項(xiàng)目的重用性。文章來源:http://www.zghlxwxcb.cn/news/detail-520564.html
掌握Spring Boot與Redis的集成技術(shù),對(duì)我們成為一名專業(yè)的后端開發(fā)者來說是非常有必要的。這是一項(xiàng)值得長(zhǎng)期研究與實(shí)踐的技能。文章來源地址http://www.zghlxwxcb.cn/news/detail-520564.html
??如果需要完整源碼請(qǐng)關(guān)注公眾號(hào)"架構(gòu)殿堂" ,回復(fù) "redis+jedis"即可獲得
??寫在最后
如果大家對(duì)相關(guān)文章感興趣,可以關(guān)注公眾號(hào)"架構(gòu)殿堂",會(huì)持續(xù)更新AIGC,java基礎(chǔ)面試題, netty, spring boot,spring cloud等系列文章,一系列干貨隨時(shí)送達(dá)!
到了這里,關(guān)于【Springboot系列】整合redis+jedis(含源碼)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!