SpringBoot集成redisson操作redis

一、配置

1.1 引入maven

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.17.0</version>
</dependency>

1.2 配置文件

spring.redis.database=0
spring.redis.password=
spring.redis.timeout=3000
#sentinel/cluster/single
spring.redis.mode=single
#连接池配置
spring.redis.pool.max-idle=16
spring.redis.pool.min-idle=8
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=3000
spring.redis.pool.conn-timeout=3000
spring.redis.pool.so-timeout=3000
spring.redis.pool.size=10
#单机配置
spring.redis.single.address=192.168.60.23:6379
#集群配置
spring.redis.cluster.scan-interval=1000
spring.redis.cluster.nodes=
spring.redis.cluster.read-mode=SLAVE
spring.redis.cluster.retry-attempts=3
spring.redis.cluster.failed-attempts=3
spring.redis.cluster.slave-connection-pool-size=64
spring.redis.cluster.master-connection-pool-size=64
spring.redis.cluster.retry-interval=1500
#哨兵配置
spring.redis.sentinel.master=business-master
spring.redis.sentinel.nodes=
spring.redis.sentinel.master-onlyWrite=true
spring.redis.sentinel.fail-max=3

1.3 配置文件读取

/**
 * @Description: 配置文件读取
 */

@ConfigurationProperties(prefix="spring.redis", ignoreUnknownFields = false)
@Data
@ToString
public class RedisProperties {

    private int database;

    /**
     * 等待节点回复命令的时间。该时间从命令发送成功时开始计时
     */
    private int timeout;

    private String password;

    private String mode;


    /**
     * 池配置
     */
    private RedisPoolProperties pool;


    /**
     * 单机信息配置
     */
    private RedisSingleProperties single;


    /**
     * 集群 信息配置
     */
    private RedisClusterProperties cluster;

    /**
     * 哨兵配置
     *
     */
    private RedisSentinelProperties sentinel;
}

/**
 * @Description: redis 池配置
 */

@Data
@ToString
public class RedisPoolProperties {

    private int maxIdle;

    private int minIdle;

    private int maxActive;

    private int maxWait;

    private int connTimeout;

    private int soTimeout;

    /**
     * 池大小
     */
    private int size;

}

/**
 * @Description: 单节点配置
 */

@Data
@ToString
public class RedisSingleProperties {

    private String address;
}

/**
 * @Description: 集群配置
 */

@Data
@ToString
public class RedisClusterProperties {

    /**
     * 集群状态扫描间隔时间,单位是毫秒
     */
    private int scanInterval;

    /**
     * 集群节点
     */
    private String nodes;

    /**
     * 默认值: SLAVE(只在从服务节点里读取)设置读取操作选择节点的模式。 可用值为: SLAVE - 只在从服务节点里读取。
     * MASTER - 只在主服务节点里读取。 MASTER_SLAVE - 在主从服务节点里都可以读取
     */
    private String readMode;

    /**
     * (从节点连接池大小) 默认值:64
     */
    private int slaveConnectionPoolSize;

    /**
     * 主节点连接池大小)默认值:64
     */
    private int masterConnectionPoolSize;

    /**
     * (命令失败重试次数) 默认值:3
     */
    private int retryAttempts;

    /**
     *命令重试发送时间间隔,单位:毫秒 默认值:1500
     */
    private int retryInterval;

    /**
     * 执行失败最大次数默认值:3
     */
    private int failedAttempts;
}

/**
 * @Description: 哨兵配置
 */

@Data
@ToString
public class RedisSentinelProperties {

    /**
     * 哨兵master 名称
     */
    private String master;

    /**
     * 哨兵节点
     */
    private String nodes;

    /**
     * 哨兵配置
     */
    private boolean masterOnlyWrite;

    /**
     *
     */
    private int failMax;

}

1.4 CacheConfiguration

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @Description:
 */

@Configuration
@EnableConfigurationProperties(RedisProperties.class)
public class CacheConfiguration {

    @Autowired
    private RedisProperties redisProperties;

    @Configuration
    @ConditionalOnClass({Redisson.class})
    @ConditionalOnExpression("'${spring.redis.mode}'=='single' or '${spring.redis.mode}'=='cluster' or '${spring.redis.mode}'=='sentinel'")
    protected class RedissonSingleClientConfiguration {

        /**
         * 单机模式 redisson 客户端
         */

        @Bean
        @ConditionalOnProperty(name="spring.redis.mode", havingValue="single")
        public RedissonClient redissonSingle() {
            Config config = new Config();
            String node = redisProperties.getSingle().getAddress();
            node = node.startsWith("redis://") ? node : "redis://" + node;
            SingleServerConfig serverConfig = config.useSingleServer()
                    .setAddress(node)
                    .setTimeout(redisProperties.getPool().getConnTimeout())
                    .setConnectionPoolSize(redisProperties.getPool().getSize())
                    .setConnectionMinimumIdleSize(redisProperties.getPool().getMinIdle());
            if(!StringUtils.isEmpty(redisProperties.getPassword())) {
                serverConfig.setPassword(redisProperties.getPassword());
            }
            return Redisson.create(config);
        }

        /**
         * 集群模式的 redisson 客户端
         *
         * @return
         */
        @Bean
        @ConditionalOnProperty(name = "spring.redis.mode", havingValue = "cluster")
        public RedissonClient redissonCluster() {
            System.out.println("cluster redisProperties:" + redisProperties.getCluster());

            Config config = new Config();
            String[] nodes = redisProperties.getCluster().getNodes().split(",");
            List<String> newNodes = new ArrayList<>(nodes.length);
            Arrays.stream(nodes).forEach((index) -> newNodes.add(
                index.startsWith("redis://") ? index : "redis://" + index)
            );

            ClusterServersConfig serverConfig = config.useClusterServers()
                    .addNodeAddress(newNodes.toArray(new String[0])
                    ).setScanInterval(
                        redisProperties.getCluster().getScanInterval()
                    ).setIdleConnectionTimeout(
                        redisProperties.getPool().getSoTimeout()
                    ).setConnectTimeout(
                        redisProperties.getPool().getConnTimeout()
                    ).setRetryAttempts(
                        redisProperties.getCluster().getRetryAttempts()
                    ).setRetryInterval(
                        redisProperties.getCluster().getRetryInterval()
                    ).setMasterConnectionPoolSize(
                            redisProperties.getCluster().getMasterConnectionPoolSize()
                    ).setSlaveConnectionPoolSize(
                            redisProperties.getCluster().getSlaveConnectionPoolSize()
                    ).setTimeout(
                            redisProperties.getTimeout()
                    );

            if (!StringUtils.isEmpty(redisProperties.getPassword())) {
                serverConfig.setPassword(redisProperties.getPassword());
            }
            return Redisson.create(config);
        }


        /**  
         * 哨兵模式 redisson 客户端
         * @return
         */
        @Bean
        @ConditionalOnProperty(name = "spring.redis.mode", havingValue = "sentinel")
        public RedissonClient redissonSentinel() {
            System.out.println("sentinel redisProperties:" + redisProperties.getSentinel());
            Config config = new Config();
            String[] nodes = redisProperties.getSentinel().getNodes().split(",");
            List<String> newNodes = new ArrayList<>(nodes.length);
            Arrays.stream(nodes).forEach((index) -> newNodes.add(
                index.startsWith("redis://") ? index : "redis://" + index)
            );

            SentinelServersConfig serverConfig = config.useSentinelServers()
                    .addSentinelAddress(newNodes.toArray(new String[0]))
                    .setMasterName(redisProperties.getSentinel().getMaster())
                    .setReadMode(ReadMode.SLAVE)
                    .setTimeout(redisProperties.getTimeout())
                    .setMasterConnectionPoolSize(redisProperties.getPool().getSize())
                    .setSlaveConnectionPoolSize(redisProperties.getPool().getSize());

            if (!StringUtils.isEmpty(redisProperties.getPassword())) {
                serverConfig.setPassword(redisProperties.getPassword());
            }
            return Redisson.create(config);
        }
    }
}

二、Redisson工具类

import org.redisson.api.*;
import org.redisson.client.codec.StringCodec;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @Description:
 */

@Component
public class RedisUtils {

    /**
     * 默认缓存时间
     */
    private static final Long DEFAULT_EXPIRED = 32000L;

    
    /**
     * 自动装配redisson client对象
     */
    @Resource
    private RedissonClient redissonClient;

    
    /**
     * 用于操作key
     * @return RKeys 对象
     */
    public RKeys getKeys() {
        return redissonClient.getKeys();
    }
    
    
    /**
     * 移除缓存
     *
     * @param key
     */
    public void delete(String key) {
        redissonClient.getBucket(key).delete();
    }

    
    /**
     * 获取getBuckets 对象
     *
     * @return RBuckets 对象
     */
    public RBuckets getBuckets() {
        return redissonClient.getBuckets();
    }

    
    /**
     * 读取缓存中的字符串,永久有效
     *
     * @param key 缓存key
     * @return 字符串
     */
    public String getStr(String key) {
        RBucket<String> bucket = redissonClient.getBucket(key);
        return bucket.get();
    }

    
    /**
     * 缓存字符串
     *
     * @param key
     * @param value
     */
    public void setStr(String key, String value) {
        RBucket<String> bucket = redissonClient.getBucket(key);
        bucket.set(value);
    }

    
    /**
     * 缓存带过期时间的字符串
     *
     * @param key     缓存key
     * @param value   缓存值
     * @param expired 缓存过期时间,long类型,必须传值
     */
    public void setStr(String key, String value, long expired) {
        RBucket<String> bucket = redissonClient.getBucket(key, StringCodec.INSTANCE);
        bucket.set(value, expired <= 0L ? DEFAULT_EXPIRED : expired, TimeUnit.SECONDS);
    }

    
    /**
     * string 操作,如果不存在则写入缓存(string方式,不带有redisson的格式信息)
     *
     * @param key     缓存key
     * @param value   缓存值
     * @param expired 缓存过期时间
     */
    public Boolean setIfAbsent(String key, String value, long expired) {
        RBucket<String> bucket = redissonClient.getBucket(key, StringCodec.INSTANCE);
        return bucket.trySet(value, expired <= 0L ? DEFAULT_EXPIRED : expired, TimeUnit.SECONDS);
    }

    
    /**
     * 如果不存在则写入缓存(string方式,不带有redisson的格式信息),永久保存
     *
     * @param key   缓存key
     * @param value 缓存值
     */
    public Boolean setIfAbsent(String key, String value) {
        RBucket<String> bucket = redissonClient.getBucket(key, StringCodec.INSTANCE);
        return bucket.trySet(value);
    }

    
    /**
     * 判断缓存是否存在
     *
     * @param key
     * @return true 存在
     */
    public Boolean isExists(String key) {
        return redissonClient.getBucket(key).isExists();
    }

    
    /**
     * 获取RList对象
     *
     * @param key RList的key
     * @return RList对象
     */
    public <T> RList<T> getList(String key) {
        return redissonClient.getList(key);
    }

    
    /**
     * 获取RMapCache对象
     *
     * @param key
     * @return RMapCache对象
     */
    public <K, V> RMapCache<K, V> getMap(String key) {
        return redissonClient.getMapCache(key);
    }

    
    /**
     * 获取RSET对象
     *
     * @param key
     * @return RSET对象
     */
    public <T> RSet<T> getSet(String key) {
        return redissonClient.getSet(key);
    }

    
    /**
     * 获取RScoredSortedSet对象
     *
     * @param key
     * @param <T>
     * @return RScoredSortedSet对象
     */
    public <T> RScoredSortedSet<T> getScoredSortedSet(String key) {
        return redissonClient.getScoredSortedSet(key);
    }
}

三、常用RKeys的API操作

每个Redisson对象实例都会有一个与之对应的Redis数据实例,可以通过调用getName方法来取得redis数据实例的名称(key),所有于Redis key相关的操作都归纳在RKeys这个接口里。

RKeys keys = client.getKeys();
//获取所有key值
Iterable<String> allKeys = keys.getKeys();
//模糊查询所有包含关键字key的值
Iterable<String> foundedKeys = keys.getKeysByPattern("key");
//删除多个key值
long numOfDeletedKeys = keys.delete("obj1", "obj2", "obj3");
//模糊删除key值
long deletedKeysAmount = keys.deleteByPattern("test?");
//随机获取key
String randomKey = keys.randomKey();
//查询当前有多少个key
long keysAmount = keys.count();

具体demo

private void getKeys() {
    RKeys keys = redisUtils.getRedisKeys();
    Iterable<String> allKeys = keys.getKeys();
    StringBuilder sb = new StringBuilder();
    for (String key : allKeys) {
        sb = sb.append(key).append(",");
    }
    log.info("所有的key:{}", sb.substring(0, sb.length() - 1));
    // 模糊查询以 map 打头的所有 key
    allKeys = keys.getKeysByPattern("map*");
    sb = new StringBuilder();
    for (String key : allKeys) {
        sb = sb.append(key).append(",");
    }
    log.info("模糊匹配到的key:{}", sb.substring(0, sb.length() - 1));
}

其中,getKeysByPattern是基于redis的scan命令实现。

四、通用对象桶Object Bucket

Redisson的分布式RBucket Java对象是一种通用对象桶,可以用来存放任意类型的对象。除了同步接口外,还提供异步(Async)、反射式(Reactive)和RxJava2标准的接口。还可以通过RBuckets接口实现批量操作多个RBucket对象。

/**
 * String 数据类型
 */
private void strDemo() {
    redisUtils.setStr(DEMO_STR, "Hello, String.");
    log.info("String 测试数据:{}", redisUtils.getStr(DEMO_STR));
    redisUtils.setStr("myBucket", "myBucketIsXxx");
    RBuckets buckets = redisUtils.getBuckets();
    Map<String, String> foundBuckets = buckets.get("myBucket*");
    Map<String, Object> map = new HashMap<>();
    map.put("myBucket1", "value1");
    map.put("myBucket2", 30L);

    // 同时保存全部通用对象桶。
    buckets.set(map);
    Map<String, String> loadedBuckets = buckets.get("myBucket1", "myBucket2", "myBucket3");
    log.info("跨桶String 测试数据:{}", loadedBuckets);
    map.put("myBucket3", 320L);
}

五、散列 Hash

基于Redisson的分布式映射结构的RMap Java对象实现了java.util.concurrent.ConcurrentMap和java.util.Map接口,与HashMap不同的是,RMap 保持了元素的插入顺序。该对象的最大容量受Redis限制,最大元素数量是4294967295个。

/**
 * Hash类型
 */
private void hashDemo() {
    RMap<Object, Object> map = redisUtils.getMap("mapDemo");
    map.put("demoId1", "123");
    map.put("demoId100", "13000");
    Object demoId1Obj = map.get("demoId1");
    log.info("Hash 测试数据:{}", demoId1Obj);
}

六、集合 Set

基于Redisson的分布式Set结构的RSet Java对象实现了java.util.Set接口,通过元素的互相状态比较保证了每个元素的唯一性,该对象的最大容量受Redis限制,最大元素数量是4294967295个。

/**
 * Set 测试
 */
private void setDemo() {
    RSet<String> set = redisUtils.getSet("setKey");
    set.add("value777");
    log.info("Set 测试数据");
    Iterator<String> iterator = set.iterator();
    while (iterator.hasNext()) {
        String next = iterator.next();
        log.info(next);
    }
}

七、列表 List

基于Redisson的分布式列表 List 结构的RList Java对象在实现了java.util.List接口的同时,确保了元素插入时的顺序,该对象的最大容量受Redis限制,最大元素数量是4294967295个。

/**
 * List数据类型
 */
private void listDemo() {
    RList<String> list = redisUtils.getList("listDemo");
    list.add("listValue1");
    list.add("listValue2");

    log.info("List 测试数据:{}", list.get(1));
}

综合示例

将上述demo放入一个API中,快速测试:

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.*;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping(value = "/redisson", method = RequestMethod.POST)
public class StudyRedissonController {

    @Resource
    private RedisUtils redisUtils;

    private static String DEMO_STR = "demoStr";

    @PostMapping("/learnRedisson")
    public void learnRedisson() {
        //三种数据结构使用示例
        strDemo();
        hashDemo();
        listDemo();
        setDemo();
        getKeys();
    }

    private void getKeys() {
        RKeys keys = redisUtils.getKeys();
        Iterable<String> allKeys = keys.getKeys();
        StringBuilder sb = new StringBuilder();
        for (String key : allKeys) {
            sb = sb.append(key).append(",");
        }
        log.info("所有的key:{}", sb.substring(0, sb.length() - 1));
        // 模糊查询以 map 打头的所有 key
        allKeys = keys.getKeysByPattern("map*");
        sb = new StringBuilder();
        for (String key : allKeys) {
            sb = sb.append(key).append(",");
        }
        log.info("模糊匹配到的key:{}", sb.substring(0, sb.length() - 1));
    }
    /**
     * Hash类型
     */
    private void hashDemo() {
        RMap<Object, Object> map = redisUtils.getMap("mapDemo");
        map.put("demoId1", "123");
        map.put("demoId100", "13000");
        Object demoId1Obj = map.get("demoId1");
        log.info("Hash 测试数据:{}", demoId1Obj);
    }

    /**
     * String 数据类型
     */
    private void strDemo() {
        redisUtils.setStr(DEMO_STR, "Hello, String.");
        log.info("String 测试数据:{}", redisUtils.getStr(DEMO_STR));
        redisUtils.setStr("myBucket", "myBucketIsXxx");
        RBuckets buckets = redisUtils.getBuckets();
        Map<String, String> foundBuckets = buckets.get("myBucket*");
        Map<String, Object> map = new HashMap<>();
        map.put("myBucket1", "value1");
        map.put("myBucket2", 30L);

        // 同时保存全部通用对象桶。
        buckets.set(map);
        Map<String, String> loadedBuckets = buckets.get("myBucket1", "myBucket2", "myBucket3");
        log.info("跨桶String 测试数据:{}", loadedBuckets);
        map.put("myBucket3", 320L);
    }

    /**
     * List数据类型
     */
    private void listDemo() {
        RList<String> list = redisUtils.getList("listDemo");
        list.add("listValue1");
        list.add("listValue2");

        log.info("List 测试数据:{}", list.get(1));
    }
    /**
     * Set 测试
     */
    private void setDemo() {
        RSet<String> set = redisUtils.getSet("setKey");
        set.add("value777");
        log.info("Set 测试数据");
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            log.info(next);
        }
    }

}

猜你喜欢

转载自blog.csdn.net/quanzhan_King/article/details/130961128