Redisson(二)SpringBoot集成Redisson

目录

一、Redis单例模式

二、Redis哨兵模式

三、Redis集群模式

四、主从模式

五、兼容多种模式的配置(重点)

1、pom

2、配置文件

(1)application.properties

(2)application-dev.properties

[(3) application-prod.properties](#(3) application-prod.properties)

3、Java配置类

4、应用


复制代码
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.15.5</version>
</dependency>

<!--
    <dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.15.5</version>
</dependency>
-->

支持Redis多种连接模式,这里以RedissonClient工具为例

一、Redis单例模式

复制代码
#单机模式
#Redis url should start with redis:// or rediss:// (for SSL connection)
my.redisson.address = redis://127.0.0.1:6379
my.redisson.password = wtyy

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RedissionConfig {

    @Value("${my.redisson.address}")
    private String address;

    @Value("${my.redisson.password}")
    private String password;

    /**
     * 所有对Redisson的使用都是通过RedissonClient对象
     */
    @Bean(destroyMethod = "shutdown")
    public RedissonClient redissonClient(){
        // 创建配置 指定redis地址及节点信息
        Config config = new Config();
        config.useSingleServer().setAddress(address);
                //.setPassword(password);
        // 根据config创建出RedissonClient实例
        RedissonClient redissonClient = Redisson.create(config);
        return redissonClient;
    }
}

二、Redis哨兵模式

复制代码
my.redisson.sentinel.schema=
my.redisson.sentinel.address = redis://xxx.xx.xxx1:19601,redis://xxx.xx.xxx2:19601,redis://xxx.xx.xxx3:19601
my.redisson.sentinel.password = N5WAXX4z9qw
my.redisson.sentinel.master = master-test
my.redisson.sentinel.database = 10

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RedissionConfig {

    @Value("${my.redisson.sentinel.address}")
    private String address;

    @Value("${my.redisson.sentinel.password}")
    private String password;

    @Value("${my.redisson.sentinel.master}")
    private String master;

    @Value("${my.redisson.sentinel.database}")
    private Integer dataBase;

    @Value("${my.redisson.sentinel.schema}")
    private String schema;

    /**
     * 所有对Redisson的使用都是通过RedissonClient对象
     */
    @Bean(destroyMethod = "shutdown")
    public RedissonClient redissonClient(){
        Config config = new Config();
        config.useSentinelServers()
                .setScanInterval(2000) // cluster state scan interval in milliseconds
                .addSentinelAddress(address.split(","))
                .setCheckSentinelsList(false)
                .setMasterName(master)
                .setPassword(password)
                .setDatabase(dataBase);
        RedissonClient redissonClient = Redisson.create(config);
        return redissonClient;
    }
}

三、Redis集群模式

复制代码
    Config config = new Config();
	config.useClusterServers()
    .setScanInterval(2000) // cluster state scan interval in milliseconds
    .addNodeAddress("redis://127.0.0.1:7000", "redis://127.0.0.1:7001")
    .addNodeAddress("redis://127.0.0.1:7002");
    RedissonClient redisson = Redisson.create(config);

四、主从模式

复制代码
    Config config = new Config();
	config.useMasterSlaveServers()
	.setMasterAddress("redis://127.0.0.1:6379")
    .addSlaveAddress("redis://127.0.0.1:6389", "redis://127.0.0.1:6332", "redis://127.0.0.1:6419")
    .addSlaveAddress("redis://127.0.0.1:6399");
    RedissonClient redisson = Redisson.create(config);

五、兼容多种模式的配置(重点)

从上面可以看到,不同的redis模式有不同的连接配置方式,如果连接变更,配置代码也要跟着变更,不够灵活,再比如有多套环境,测试环境和生产环境使用的是不同的redis模式,所以需要考虑配置兼容问题。下面的配置适用于所有模式。

1、pom

因为使用到了 RedisProperties,所以需要引入 spring-boot-starter-data-redis

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>redis-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.4</version>
        <relativePath/>
    </parent>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

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

        <!--连接池依赖-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.11.1</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>


        <!--hutool工具-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.15</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>


        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.10.1</version>
        </dependency>
    </dependencies>

</project>
2、配置文件

按照 org.springframework.boot.autoconfigure.data.redis.RedisProperties 规则配置。源码:

复制代码
package org.springframework.boot.autoconfigure.data.redis;

@ConfigurationProperties(
    prefix = "spring.data.redis"
)
public class RedisProperties {
    private int database = 0;
    private String url;
    private String host = "localhost";
    private String username;
    private String password;
    private int port = 6379;
    private Duration timeout;
    private Duration connectTimeout;
    private String clientName;
    private ClientType clientType;
    private Sentinel sentinel;
    private Cluster cluster;
    private final Ssl ssl = new Ssl();
    private final Jedis jedis = new Jedis();
    private final Lettuce lettuce = new Lettuce();

    ......
}

这里有两套环境:dev和prod

(1)application.properties
复制代码
spring.profiles.active=dev
(2)application-dev.properties
复制代码
spring.data.redis.host=127.0.0.1
spring.data.redis.port=6379
spring.data.redis.password=
spring.data.redis.lettuce.pool.max-active=8
spring.data.redis.lettuce.pool.max-wait=-1
spring.data.redis.lettuce.pool.max-idle=8
spring.data.redis.lettuce.pool.min-idle=0
spring.data.redis.lettuce.pool.enabled=true
spring.data.redis.lettuce.pool.time-between-eviction-runs=30s
(3) application-prod.properties
复制代码
spring.data.redis.cluster.nodes=xxx.xxx.xx.xxx:6379
spring.data.redis.cluster.max-redirects=3
spring.data.redis.timeout=60S
spring.data.redis.lettuce.pool.max-wait=2S
spring.data.redis.lettuce.pool.max-active=1200
spring.data.redis.lettuce.pool.max-idle=400
spring.data.redis.lettuce.pool.min-idle=50
# spring.redis.lettuce.pool.time-between-eviction-runs=200
spring.data.redis.lettuce.pool.enabled=true
spring.data.redis.lettuce.pool.time-between-eviction-runs=30s
spring.data.redis.lettuce.cluster.refresh.adaptive=true
spring.data.redis.lettuce.cluster.refresh.period=60s
3、Java配置类

读取配置文件中 spring.data.redis 开头的配置,并加以判断。

复制代码
package org.example.config;

import io.micrometer.common.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Slf4j
@Configuration
public class RedissonConfig {

    @Autowired
    RedisProperties redisProperties;

    private static final String REDIS_PROTOCOL_PREFIX = "redis://";

    private static final String REDISS_PROTOCOL_PREFIX = "rediss://";

    @Bean(destroyMethod = "shutdown")
    public RedissonClient redisson() {
        Config config;
        Method clusterMethod = ReflectionUtils.findMethod(RedisProperties.class, "getCluster");
        Method timeoutMethod = ReflectionUtils.findMethod(RedisProperties.class, "getTimeout");
        Object timeoutValue = ReflectionUtils.invokeMethod(timeoutMethod, redisProperties);
        int timeout;
        if (null == timeoutValue) {
            timeout = 10000;
        } else if (!(timeoutValue instanceof Integer)) {
            Method millisMethod = ReflectionUtils.findMethod(timeoutValue.getClass(), "toMillis");
            timeout = ((Long) ReflectionUtils.invokeMethod(millisMethod, timeoutValue)).intValue();
        } else {
            timeout = (Integer) timeoutValue;
        }

        if (redisProperties.getSentinel() != null) {
            Method nodesMethod =
                    ReflectionUtils.findMethod(RedisProperties.Sentinel.class, "getNodes");
            Object nodesValue =
                    ReflectionUtils.invokeMethod(nodesMethod, redisProperties.getSentinel());

            String[] nodes;
            if (nodesValue instanceof String) {
                nodes = convert(Arrays.asList(((String) nodesValue).split(",")));
            } else {
                nodes = convert((List<String>) nodesValue);
            }

            config = new Config();
            config.useSentinelServers()
                    .setMasterName(redisProperties.getSentinel().getMaster())
                    .addSentinelAddress(nodes)
                    .setDatabase(redisProperties.getDatabase())
                    .setConnectTimeout(timeout)
                    .setPassword(redisProperties.getPassword());
        } else if (clusterMethod != null
                && ReflectionUtils.invokeMethod(clusterMethod, redisProperties) != null) {
            Object clusterObject = ReflectionUtils.invokeMethod(clusterMethod, redisProperties);
            Method nodesMethod = ReflectionUtils.findMethod(clusterObject.getClass(), "getNodes");
            List<String> nodesObject =
                    (List) ReflectionUtils.invokeMethod(nodesMethod, clusterObject);

            String[] nodes = convert(nodesObject);

            config = new Config();
            config.useClusterServers()
                    .addNodeAddress(nodes)
                    .setConnectTimeout(timeout)
                    .setPassword(redisProperties.getPassword());
        } else {
            config = new Config();
            String prefix = REDIS_PROTOCOL_PREFIX;
            Method method = ReflectionUtils.findMethod(RedisProperties.class, "isSsl");
            if (method != null && (Boolean) ReflectionUtils.invokeMethod(method, redisProperties)) {
                prefix = REDISS_PROTOCOL_PREFIX;
            }

            String password =
                    StringUtils.isBlank(redisProperties.getPassword())
                            ? null
                            : redisProperties.getPassword();
            config.useSingleServer()
                    .setAddress(
                            prefix + redisProperties.getHost() + ":" + redisProperties.getPort())
                    .setConnectTimeout(timeout)
                    .setDatabase(redisProperties.getDatabase())
                    .setPassword(password);
        }

        return Redisson.create(config);
    }

    private String[] convert(List<String> nodesObject) {
        List<String> nodes = new ArrayList<String>(nodesObject.size());
        for (String node : nodesObject) {
            if (!node.startsWith(REDIS_PROTOCOL_PREFIX)
                    && !node.startsWith(REDISS_PROTOCOL_PREFIX)) {
                nodes.add(REDIS_PROTOCOL_PREFIX + node);
            } else {
                nodes.add(node);
            }
        }
        return nodes.toArray(new String[nodes.size()]);
    }
}

这里用了反射,其实RedisProperties对象已经拿到了,直接从 redisProperties中get也是可以的:

复制代码
RedisProperties.Cluster cluster = redisProperties.getCluster();
4、应用
复制代码
import com.alibaba.fastjson.JSON;
import org.example.dto.UserDTO;
import org.example.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest(classes = {Main.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
public class RedissonTest {

    @Autowired
    private RedissonClient redissonClient;

    @Test
    public void  testString(){
        RBucket<Object> bucket = redissonClient.getBucket("test");
        bucket.set("这是value");
        System.out.println(bucket.get());
    }
}
5、与RedisTemplate并存使用

这个demo引入了 spring-boot-starter-data-redis,所以可以直接使用RedisTemplate:

复制代码
@SpringBootTest(classes = {Main.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
public class MyTest {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private UserService userService;

    @Test
    public void  testString(){
        String key = "string-name";
        //存
        String value = "这是value123";
        stringRedisTemplate.opsForValue().set(key,value);
        //取
        Object valueObj = stringRedisTemplate.opsForValue().get(key);
        System.out.println("value为:" + valueObj);
    }
}
相关推荐
Full Stack Developme10 分钟前
java.nio 包详解
java·python·nio
零千叶27 分钟前
【面试】Java JVM 调优面试手册
java·开发语言·jvm
代码充电宝36 分钟前
LeetCode 算法题【简单】290. 单词规律
java·算法·leetcode·职场和发展·哈希表
li37149089040 分钟前
nginx报400bad request 请求头过大异常处理
java·运维·nginx
摇滚侠43 分钟前
Spring Boot 项目, idea 控制台日志设置彩色
java·spring boot·intellij-idea
Aevget1 小时前
「Java EE开发指南」用MyEclipse开发的EJB开发工具(二)
java·ide·java-ee·eclipse·myeclipse
黄昏晓x2 小时前
C++----多态
java·jvm·c++
Brookty2 小时前
【算法】前缀和
java·学习·算法·前缀和·动态规划
少许极端2 小时前
算法奇妙屋(七)-字符串操作
java·开发语言·数据结构·算法·字符串操作
懒羊羊不懒@2 小时前
Java基础语法—字面量、变量详解、存储数据原理
java·开发语言