springboot2默认已经使用了lettuce-core,没有使用jedis和Redisson,springboot1使用的是jedis。

我使用的springboot版本是2.6.14。(对应的lettuce版本为6.1.10.RELEASE,对应jedis版本为3.7.1)

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
		    <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

连接到Redis

您可以像注入任何其他Spring Bean一样,注入一个自动配置的RedisConnectionFactory、StringRedisTemplate或普通RedistTemplate实例。下面的清单显示了这样一个bean的示例:



单机模式的配置

spring.redis.host=localhost
spring.redis.port=6379
spring.redis.database=0
spring.redis.username=user
spring.redis.password=secret
spring:
  redis:
    host: "localhost"
    port: 6379
    database: 0
    username: "user"
    password: "secret"
@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
        //解决序列化丢失类型信息
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        //反序列化
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);

        //使用Jackson2JsonRedisSerialize 替换默认序列化(默认采用的是JDK序列化)
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);


        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }
}


/**
 * @author 
 * 配置redis序列化json
 */
@Configuration
public class RedisConfiguration {


    @Bean
    /**
     * 若有相同类型的Bean时,优先使用此注解标注的Bean
     */
    @Primary
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // 为了开发方便,一般直接使用<String, Object>
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        // 配置具体的序列化方式
        // JSON解析任意对象
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会抛出异常
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        // 设置日期格式
        om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // String的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();


        // key采用String的序列化
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化
        template.setHashKeySerializer(stringRedisSerializer);
        // value的序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        // 设置所有配置
        template.afterPropertiesSet();

        return template;
    }
}







哨兵(sentinel)模式的配置

spring:
  redis:
    sentinel:
      master: mymaster
      nodes: 
        - 127.0.0.1:27001
        - 127.0.0.1:27001
        - 127.0.0.1:27001
spring:
  redis:
    sentinel:
      master: mymaster
      nodes: 192.168.211.158:6382,192.168.211.158:6383,192.168.211.158:6384

配置类中添加以下配置

@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(){
    return configBuilder -> configBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}

这里的ReadFrom是配置Redis的读取策略,是一个枚举类,有以下选择

  • MASTER:从主节点读取
  • MASTER_PREFERRED:优先从master节点读取,master不可用才读取slave节点
  • REPLICA:从slave节点读取
  • REPLICA_PREFERRED:优先从slave节点读取,所有slave不可用才读取master(推荐)

至此,配置已经完成,再使用redisTemplate时读会从slave节点,写会从master节点


@Configuration
public class RedisConfiguration {

    /**
     *
     *  配置redis序列化json
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    @Primary    //若有相同类型的Bean时,优先使用此注解标注的Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // 为了开发方便,一般直接使用<String, Object>
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        // 配置具体的序列化方式
        // JSON解析任意对象
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        // 设置日期格式
        om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // String的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();


        //key采用String的序列化
        template.setKeySerializer(stringRedisSerializer);
        //value的序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        
        //hash的key也采用String的序列化
        template.setHashKeySerializer(stringRedisSerializer);
        //hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        
        //设置所有配置
        // 设置支持事物
        redisTemplate.setEnableTransactionSupport(true);
        template.afterPropertiesSet();

        return template;
    }

    /**
     * 配置读写分离
     * @param redisProperties
     * @return
     */
    @Bean
    public RedisConnectionFactory lettuceConnectionFactory(RedisProperties redisProperties) {
        // 配置哨兵节点以及主节点
        RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration(
                redisProperties.getSentinel().getMaster(), new HashSet<>(redisProperties.getSentinel().getNodes())
        );

        // 配置读写分离
        LettucePoolingClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder()
                // 读写分离,这里的ReadFrom是配置Redis的读取策略,是一个枚举,包括下面选择
                // MASTER   仅读取主节点
                // MASTER_PREFERRED   优先读取主节点,如果主节点不可用,则读取从节点
                // REPLICA_PREFERRED   优先读取从节点,如果从节点不可用,则读取主节点
                // REPLICA   仅读取从节点
                // NEAREST   从最近节点读取
                // ANY   从任意一个从节点读取
                .readFrom(ReadFrom.REPLICA_PREFERRED)
                .build();

        return new LettuceConnectionFactory(redisSentinelConfiguration, lettuceClientConfiguration);
    }

}













集群(cluster)模式的配置

spring:
  redis:
    cluster:
      # 集群节点
      nodes: 192.168.211.158:6382,192.168.211.158:6383,192.168.211.158:6384,192.168.211.158:6385,192.168.211.158:6386,192.168.211.158:6387
      # 最大重定向次数
      max-redirects: 5
    # 密码
    password: myredis
    lettuce:
      pool:
        min-idle: 0
        max-active: 8
        max-wait: -1
        max-idle: 8
        enabled: true
spring:
  redis:
    cluster:
      nodes: # 指定分片集群中的每个节点信息
        - 127.0.0.1:7:7001
        - 127.0.0.1:7:7002
        - 127.0.0.1:7:7003
        - 127.0.0.1:7:8001
        - 127.0.0.1:7:8002
        - 127.0.0.1:7:8003
spring:
  redis:
    # redis哨兵配置
    sentinel:
      # 主节点名称
      master: mymaster
      nodes:
        - 192.168.159.100:26380
        - 192.168.159.100:26381
        - 192.168.159.100:26382
#    # 集群的部署方式
#    cluster:
#      nodes:
#        - 192.168.158.100:6380
#        - 192.168.158.100:6381
#        - 192.168.158.100:6382
#      # #最大重定向次数(由于集群中数据存储在多个节点,所以在访问数据时需要通过转发进行数据定位)
#      max-redirects: 2
#    lettuce:
#      pool:
#        max-idle: 10   # 连接池中的最大空闲连接
#        max-wait: 500   # 连接池最大阻塞等待时间(使用负值表示没有限制)
#        max-active: 8   # 连接池最大连接数(使用负值表示没有限制)
#        min-idle: 0   # 连接池中的最小空闲连接









相对比较完整的redis配置参数

spring:
  redis:
    host: localhost
    port: 6379
    username: user
    password: 123456
    database: 0
    ssl: false
    timeout: 120
    connectTimeout: 120
    clientName: aaa
	(type,LETTUCE,JEDIS)
	
    pool:
      enable: true
      maxIdle: 100
      minIdle: 0
      maxActive:100
      maxWait:100
	  
      maxTotal: 100
      maxWaitMillis: 500
      testOnBorrow: false
      testOnReturn: true
      testWhileIdle: true
	  
    sentinel:
      master: bebepay_redis
      nodes:
        --
      password: 123456
	  
    cluster:
      nodes:
	    --
      maxRedirects:
	  
    jedis: 
      
    lettuce: 
      

RedisTemplate和StringRedisTemplate是我们项目中常用的redis操作类。他们的关系如下图所示:

springboot之RedisTemplate的访问单机,哨兵,集群模式_spring

//<String, String>, 限定了只能操作key和value都是string类型的数据
public class StringRedisTemplate extends RedisTemplate<String, String> {
       //构造方法中,定义序列化器stringSerializer 
	public StringRedisTemplate() {
		RedisSerializer<String> stringSerializer = new StringRedisSerializer();
		setKeySerializer(stringSerializer);
		setValueSerializer(stringSerializer);
		setHashKeySerializer(stringSerializer);
		setHashValueSerializer(stringSerializer);
	}
    ......
}


Redis 支持的 Java 客户端有以下几种:

1. Jedis
2. Lettuce
3. Redisson
4. Redisson Reactive

1. Jedis

Jedis 是 Redis 的 Java 客户端。它支持完整的 Redis API,提供了良好的性能和易用性。下面是一个简单的 Jedis 示例:

import redis.clients.jedis.Jedis;
 
public class JedisExample {
    public static void main(String[] args) {
        // 连接 Redis
        Jedis jedis = new Jedis("localhost", 6379);
        // 设置键值对
        jedis.set("foo", "bar");
        // 获取键值对
        String value = jedis.get("foo");
        System.out.println(value);
        // 关闭连接
        jedis.close();
    }
}

2. Lettuce

Lettuce 是一个高性能的 Redis 客户端。它使用 Netty 作为底层通信框架,并支持异步、同步和响应式编程模式。下面是一个简单的 Lettuce 示例:

import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
 
public class LettuceExample {
    public static void main(String[] args) {
        // 连接 Redis
        RedisClient redisClient = RedisClient.create("redis://localhost:6379");
        StatefulRedisConnection connection = redisClient.connect();
        RedisCommands commands = connection.sync();
        // 设置键值对
        commands.set("foo", "bar");
        // 获取键值对
        String value = commands.get("foo");
        System.out.println(value);
        // 关闭连接
        connection.close();
        redisClient.shutdown();
    }
}

3. Redisson

Redisson 是一个基于 Redis 的分布式 Java 对象和服务框架。它提供了分布式锁、分布式集合、分布式对象等功能,支持异步和同步编程模式。下面是一个简单的 Redisson 示例:

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
 
public class RedissonExample {
    public static void main(String[] args) {
        // 连接 Redis
        Config config = new Config();
        config.useSingleServer().setAddress("redis://localhost:6379");
        RedissonClient redissonClient = Redisson.create(config);
        // 获取 String 对象
        String value = redissonClient.getBucket("foo").get();
        System.out.println(value);
        // 关闭连接
        redissonClient.shutdown();
    }
}

4. Redisson Reactive

Redisson Reactive 是 Redisson 的响应式编程模式扩展。它可以与 Java 8 的流式 API 和 Reactor 整合,提供了基于响应式编程模式的分布式 Redis 功能。下面是一个简单的 Redisson Reactive 示例:

import org.redisson.Redisson;
import org.redisson.api.RedissonReactiveClient;
import org.redisson.config.Config;
 
public class RedissonReactiveExample {
    public static void main(String[] args) {
        // 连接 Redis
        Config config = new Config();
        config.useSingleServer().setAddress("redis://localhost:6379");
        RedissonReactiveClient redissonReactiveClient = Redisson.createReactive(config);
        // 获取 String 对象
        redissonReactiveClient.getBucket("foo").get().subscribe(value -> System.out.println(value));
        // 关闭连接
        redissonReactiveClient.shutdown();
    }
}

5. Spring Data Redis Reactive 技术栈

我们可以通过导入 spring-boot-starter-data-redis-reactive 依赖来集成 Spring Data Reactive Redis 模块

ReactiveRedisOperations 中定义了一批针对 Redis 各种数据结构的操作方法,如下所示。

public interface ReactiveRedisOperations<K, V> {
 
    <HK, HV> ReactiveHashOperations<K, HK, HV> opsForHash();
	<K, HK, HV> ReactiveHashOperations<K, HK, HV> opsForHash(RedisSerializationContext<K, ?> serializationContext);
 
    ReactiveListOperations<K, V> opsForList();
	<K, V> ReactiveListOperations<K, V> opsForList(RedisSerializationContext<K, V> serializationContext);
 
    ReactiveSetOperations<K, V> opsForSet();
	<K, V> ReactiveSetOperations<K, V> opsForSet(RedisSerializationContext<K, V> serializationContext);
 
    ReactiveValueOperations<K, V> opsForValue();
	<K, V> ReactiveValueOperations<K, V> opsForValue(RedisSerializationContext<K, V> serializationContext);
 
    ReactiveZSetOperations<K, V> opsForZSet();
	<K, V> ReactiveZSetOperations<K, V> opsForZSet(RedisSerializationContext<K, V> serializationContext);
 
…
}


在 Redis 中,常见的 ConnectionFactory 有两种,一种是传统的 JedisConnectionFactory,而另一种就是新型的 LettuceConnectionFactory。LettuceConnectionFactory 基于 Netty 创建连接实例,可以在多个线程间实现线程安全,满足多线程环境下的并发访问要求。更为重要的是,LettuceConnectionFactory 同时支持响应式的数据访问用法,它是 ReactiveRedisConnectionFactory 接口的一种实现。Lettuce 也是目前 Redis 唯一的响应式 Java 连接器。Lettuce 4.x 版本使用 RxJava 作为底层响应式流实现方案。但是,该库的 5.x 分支切换到了 Project Reactor。

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

springboot之RedisTemplate的访问单机,哨兵,集群模式_spring_02

在上图中,我们同时看到 luttuce-core 组件中使用了 Project Reactor 框架中的 reactor-core 组件,这点与前面介绍的技术栈是完全一致的。

为了获取连接,我们需要初始化 LettuceConnectionFactory。LettuceConnectionFactory 类的最简单使用方法如下所示。

@Bean
public ReactiveRedisConnectionFactory lettuceConnectionFactory() {
	    return new LettuceConnectionFactory();
}
	 
@Bean
public ReactiveRedisConnectionFactory lettuceConnectionFactory() {
        return new LettuceConnectionFactory("localhost", 6379);
}

当然,LettuceConnectionFactory 也提供了一系列配置项供我们在初始化时进行设置,示例代码如下所示,我们可以对连接的安全性、超时时间等参数进行设置。

@Bean
public ReactiveRedisConnectionFactory lettuceConnectionFactory() {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setDatabase(database);
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(port);
     redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
        LettuceClientConfiguration.LettuceClientConfigurationBuilder lettuceClientConfigurationBuilder = LettuceClientConfiguration
               .builder();
        LettuceConnectionFactory factory = new LettuceConnectionFactory(redisStandaloneConfiguration,
               lettuceClientConfigurationBuilder.build());
	        return factory;
}

有了 LettuceConnectionFactory,就可以用它来进一步初始化 ReactiveRedisTemplate。ReactiveRedisTemplate 的创建方式如下所示。与传统 RedisTemplate 创建方式的主要区别在于,ReactiveRedisTemplate 依赖于 ReactiveRedisConnectionFactory 来获取 ReactiveRedisConnection。

@Bean
ReactiveRedisTemplate<String, String> 
reactiveRedisTemplate(ReactiveRedisConnectionFactory factory) {
return new ReactiveRedisTemplate<>(factory, 
	RedisSerializationContext.string());
    }
 
    @Bean
    ReactiveRedisTemplate<String, Account> redisOperations(ReactiveRedisConnectionFactory factory) {
	Jackson2JsonRedisSerializer<Account> serializer = new 
	Jackson2JsonRedisSerializer<>(Account.class);
 
        RedisSerializationContext.RedisSerializationContextBuilder
	<String, Account> builder = RedisSerializationContext
        .newSerializationContext(new StringRedisSerializer());
 
    RedisSerializationContext<String, Account> context = 
	builder.value(serializer).build();
 
        return new ReactiveRedisTemplate<>(factory, context);
}

springboot之工程定制RedisTemplate的集群访问模式

定制RedisTemplate访问哨兵集群模式

在pom文件中引入redis的启动依赖

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

在配置文件中配置sentinel的相关信息

spring:
  redis:
    sentinel:
      master: mymaster
      nodes: 
        - 127.0.0.1:27001
        - 127.0.0.1:27001
        - 127.0.0.1:27001
  • mymaster对应了sentinel的配置文件中配置的主节点名字
  • 这里面配置类所有的哨兵服务器地址

配置类中添加以下配置

@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(){
    return configBuilder -> configBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}

这里的ReadFrom是配置Redis的读取策略,是一个枚举类,有以下选择

MASTER:从主节点读取
MASTER_PREFERRED:优先从master节点读取,master不可用才读取slave节点
REPLICA:从slave节点读取
REPLICA_PREFERRED:优先从slave节点读取,所有slave不可用才读取master(推荐)

至此,配置已经完成,再使用redisTemplate时读会从slave节点,写会从master节点


定制RedisTemplate访问分片集群模式

引入依赖

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

配置文件配置分片集群地址

spring:
  redis:
    cluster:
      nodes: # 指定分片集群中的每个节点信息
        - 127.0.0.1:7:7001
        - 127.0.0.1:7:7002
        - 127.0.0.1:7:7003
        - 127.0.0.1:7:8001
        - 127.0.0.1:7:8002
        - 127.0.0.1:7:8003

配置类中配置读写分离

@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(){
    return configBuilder -> configBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}