Working with Objects through RedisTemplate

大多数用户都可能使用 RedisTemplate 及其相应的包 org.springframework.data.redis.core 或其响应式变体 ReactiveRedisTemplate。模板实际上是 Redis 模块的核心类,因为它具有丰富的功能集。模板为 Redis 交互提供了高级抽象。虽然 [Reactive]RedisConnection 提供了接受和返回二进制值(byte 数组)的底层方法,但模板负责序列化和连接管理,从而使用户不必处理此类细节。 RedisTemplate 类实现了 RedisOperations 接口,其响应变体 ReactiveRedisTemplate 实现了 ReactiveRedisOperations

通过“ [Reactive]RedisOperations”接口引用“ [Reactive]RedisTemplate”实例上的操作是首选方式。

此外,模板提供了操作视图(遵循 Redis 命令 reference 中的分组),为针对特定类型或特定键(通过 KeyBound 接口)工作提供了丰富的泛化接口,如下表所示: .Operational views

Imperative
Interface Description

Key Type Operations

GeoOperations

Redis 地理空间操作,例如 GEOADDGEORADIUS……​

HashOperations

Redis hash operations

HyperLogLogOperations

类似 PFADDPFCOUNT…​ 的 Redis HyperLogLog 操作

ListOperations

Redis list operations

SetOperations

Redis set operations

ValueOperations

Redis 字符串(或值)操作

ZSetOperations

Redis 有序集合(或 zset)操作

Key Bound Operations

BoundGeoOperations

Redis 密钥绑定的地理空间操作

BoundHashOperations

Redis 哈希密钥绑定的操作

BoundKeyOperations

Redis key bound operations

BoundListOperations

Redis 列表密钥绑定的操作

BoundSetOperations

Redis 集合密钥绑定的操作

BoundValueOperations

Redis 字符串(或值)密钥绑定的操作

BoundZSetOperations

Redis 有序集合(或 zset)密钥绑定的操作

Reactive
Interface Description

Key Type Operations

ReactiveGeoOperations

GEOADDGEORADIUS 等 Redis 地理空间操作

ReactiveHashOperations

Redis hash operations

ReactiveHyperLogLogOperations

像 (PFADDPFCOUNT 等的 Redis HyperLogLog 操作

ReactiveListOperations

Redis list operations

ReactiveSetOperations

Redis set operations

ReactiveValueOperations

Redis 字符串(或值)操作

ReactiveZSetOperations

一旦配置,模板就是线程安全的,可以在多个实例中重用。 RedisTemplate 在其大多数操作中使用基于 Java 的序列化器。这意味着由模板编写的或读取的任何对象都将通过 Java 进行序列化和反序列化。 你可以在模板上更改序列化机制,Redis 模块提供了几种实现,这些实现可在 org.springframework.data.redis.serializer 包中找到。有关更多信息,请参阅 redis:serializer。还可以将任何序列化器设置为 null,并通过将 enableDefaultSerializer 属性设置为 false 来使用原始字节数组的 RedisTemplate。请注意,模板要求所有键都不能为空。但是,只要底层序列化器接受,值就可以为空。阅读每个序列化器 的 Javadoc 以了解更多信息。 对于需要特定模板视图的情况,将视图声明为依赖项并注入模板。容器会自动执行转换,消除 opsFor[X] 调用,如下面的示例所示:

Configuring Template API
  • Java Imperative

  • Java Reactive

  • XML

@Configuration
class MyConfig {

  @Bean
  LettuceConnectionFactory connectionFactory() {
    return new LettuceConnectionFactory();
  }

  @Bean
  RedisTemplate<String, String> redisTemplate(RedisConnectionFactory connectionFactory) {

    RedisTemplate<String, String> template = new RedisTemplate<>();
    template.setConnectionFactory(connectionFactory);
    return template;
  }
}
@Configuration
class MyConfig {

  @Bean
  LettuceConnectionFactory connectionFactory() {
    return new LettuceConnectionFactory();
  }

  @Bean
  ReactiveRedisTemplate<String, String> ReactiveRedisTemplate(ReactoveRedisConnectionFactory connectionFactory) {
    return new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext.string());
  }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"/>
  <!-- redis template definition -->
  <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref="redisConnectionFactory"/>
  ...

</beans>
Pushing an item to a List using [Reactive]RedisTemplate
  • Imperative

  • Reactive

public class Example {

  // inject the actual operations
  @Autowired
  private RedisOperations<String, String> operations;

  // inject the template as ListOperations
  @Resource(name="redisTemplate")
  private ListOperations<String, String> listOps;

  public void addLink(String userId, URL url) {
    listOps.leftPush(userId, url.toExternalForm());
  }
}
public class Example {

  // inject the actual template
  @Autowired
  private ReactiveRedisOperations<String, String> operations;

  public Mono<Long> addLink(String userId, URL url) {
    return operations.opsForList().leftPush(userId, url.toExternalForm());
  }
}

String-focused Convenience Classes

由于 Redis 中存储的键和值通常是 java.lang.String,因此 Redis 模块为 RedisConnectionRedisTemplate 分别提供了两个扩展,即 StringRedisConnection(及其 DefaultStringRedisConnection 实现)和 StringRedisTemplate,作为针对复杂字符串操作的便捷一站式解决方案。除了绑定到 String 键之外,模板和连接在下面使用 StringRedisSerializer,这意味着存储的键和值都是人类可读的(假设 Redis 和代码中都使用了相同的编码)。以下清单显示了一个示例:

  • Java Imperative

  • Java Reactive

  • XML

@Configuration
class RedisConfiguration {

  @Bean
  LettuceConnectionFactory redisConnectionFactory() {
    return new LettuceConnectionFactory();
  }

  @Bean
  StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {

    StringRedisTemplate template = new StringRedisTemplate();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
  }
}
@Configuration
class RedisConfiguration {

  @Bean
  LettuceConnectionFactory redisConnectionFactory() {
    return new LettuceConnectionFactory();
  }

  @Bean
  ReactiveStringRedisTemplate reactiveRedisTemplate(ReactiveRedisConnectionFactory factory) {
    return new ReactiveStringRedisTemplate<>(factory);
  }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"/>

  <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate" p:connection-factory-ref="redisConnectionFactory"/>

</beans>
  • Imperative

  • Reactive

public class Example {

  @Autowired
  private StringRedisTemplate redisTemplate;

  public void addLink(String userId, URL url) {
    redisTemplate.opsForList().leftPush(userId, url.toExternalForm());
  }
}
public class Example {

  @Autowired
  private ReactiveStringRedisTemplate redisTemplate;

  public Mono<Long> addLink(String userId, URL url) {
    return redisTemplate.opsForList().leftPush(userId, url.toExternalForm());
  }
}

与其他 Spring 模板一样,RedisTemplateStringRedisTemplate 允许你通过 RedisCallback 接口直接与 Redis 通信。此功能为你提供了完全控制,因为它直接与 RedisConnection 通信。请注意,当使用 StringRedisTemplate 时,回调会收到 StringRedisConnection 的实例。以下示例演示如何使用 RedisCallback 接口:

public void useCallback() {

  redisOperations.execute(new RedisCallback<Object>() {
    public Object doInRedis(RedisConnection connection) throws DataAccessException {
      Long size = connection.dbSize();
      // Can cast to StringRedisConnection if using a StringRedisTemplate
      ((StringRedisConnection)connection).set("key", "value");
    }
   });
}

Serializers

从框架的角度来看,Redis 中存储的数据只是字节。虽然 Redis 本身支持各种类型,但大多数情况下,这些类型指代的是数据的存储方式,而不是它表示的内容。用户要自己决定是将信息转换为字符串还是其他任何对象。

在 Spring Data 中,用户(自定义)类型和原始数据(反之亦然)之间的转换由 Spring Data Redis 在 org.springframework.data.redis.serializer 包中处理。

此包包含两种类型的序列化器,顾名思义,这些序列化器负责序列化过程:

  • 基于 RedisSerializer 的双向序列化器。

  • 使用 RedisElementReaderRedisElementWriter 的元素读取器和写入器。

这些变体之间的主要区别在于 RedisSerializer 主要序列化为 byte[],而读取器和写入器使用 ByteBuffer

有多种实现可用(包括本文档中已提及的两种):

  • JdkSerializationRedisSerializer,默认情况下用于 RedisCacheRedisTemplate

  • the StringRedisSerializer.

但是,可以使用 OxmSerializer 进行对象/XML 映射,可以通过 Spring {spring-framework-docs}/data-access.html#oxm[OXM] 支持或使用 Jackson2JsonRedisSerializerGenericJackson2JsonRedisSerializerJSON 格式存储数据。

请注意,存储格式不限于值。它可以毫无限制地用于键、值或哈希。

默认情况下,RedisCacheRedisTemplate 被配置为使用 Java 本机序列化。Java 本机序列化允许运行远程代码,原因是注入未经验证的字节代码的有效负载会利用易受攻击的库和类。处理输入时,可能会导致在反序列化步骤中在应用程序中运行不需要的代码。因此,不要在不受信任的环境中使用序列化。通常,我们强烈建议使用任何其他消息格式(例如 JSON)。 如果您担心由于 Java 序列化而引起的安全性漏洞,请考虑核心 JVM 级别的一般用途序列化过滤机制: