Working with Objects through RedisTemplate

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

Most users are likely to use RedisTemplate and its corresponding package, org.springframework.data.redis.core or its reactive variant ReactiveRedisTemplate. The template is, in fact, the central class of the Redis module, due to its rich feature set. The template offers a high-level abstraction for Redis interactions. While [Reactive]RedisConnection offers low-level methods that accept and return binary values (byte arrays), the template takes care of serialization and connection management, freeing the user from dealing with such details.

RedisTemplate 类实现了 RedisOperations 接口,其响应变体 ReactiveRedisTemplate 实现了 ReactiveRedisOperations

The RedisTemplate class implements the RedisOperations interface and its reactive variant ReactiveRedisTemplate implements ReactiveRedisOperations.

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

The preferred way to reference operations on a [Reactive]RedisTemplate instance is through the [Reactive]RedisOperations interface.

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

Moreover, the template provides operations views (following the grouping from the Redis command reference) that offer rich, generified interfaces for working against a certain type or certain key (through the KeyBound interfaces) as described in the following table: .Operational views

Imperative
Interface Description

Key Type Operations

GeoOperations

Redis geospatial operations, such as GEOADD, GEORADIUS,…​

HashOperations

Redis hash operations

HyperLogLogOperations

Redis HyperLogLog operations, such as PFADD, PFCOUNT,…​

ListOperations

Redis list operations

SetOperations

Redis set operations

ValueOperations

Redis string (or value) operations

ZSetOperations

Redis zset (or sorted set) operations

Key Bound Operations

BoundGeoOperations

Redis key bound geospatial operations

BoundHashOperations

Redis hash key bound operations

BoundKeyOperations

Redis key bound operations

BoundListOperations

Redis list key bound operations

BoundSetOperations

Redis set key bound operations

BoundValueOperations

Redis string (or value) key bound operations

BoundZSetOperations

Redis zset (or sorted set) key bound operations

Reactive
Interface Description

Key Type Operations

ReactiveGeoOperations

Redis geospatial operations such as GEOADD, GEORADIUS, and others)

ReactiveHashOperations

Redis hash operations

ReactiveHyperLogLogOperations

Redis HyperLogLog operations such as (PFADD, PFCOUNT, and others)

ReactiveListOperations

Redis list operations

ReactiveSetOperations

Redis set operations

ReactiveValueOperations

Redis string (or value) operations

ReactiveZSetOperations

一旦配置,模板就是线程安全的,可以在多个实例中重用。

Once configured, the template is thread-safe and can be reused across multiple instances.

RedisTemplate 在其大多数操作中使用基于 Java 的序列化器。这意味着由模板编写的或读取的任何对象都将通过 Java 进行序列化和反序列化。

RedisTemplate uses a Java-based serializer for most of its operations. This means that any object written or read by the template is serialized and deserialized through Java.

你可以在模板上更改序列化机制,Redis 模块提供了几种实现,这些实现可在 org.springframework.data.redis.serializer 包中找到。有关更多信息,请参阅 redis:serializer。还可以将任何序列化器设置为 null,并通过将 enableDefaultSerializer 属性设置为 false 来使用原始字节数组的 RedisTemplate。请注意,模板要求所有键都不能为空。但是,只要底层序列化器接受,值就可以为空。阅读每个序列化器 的 Javadoc 以了解更多信息。

You can change the serialization mechanism on the template, and the Redis module offers several implementations, which are available in the org.springframework.data.redis.serializer package. See redis:serializer for more information. You can also set any of the serializers to null and use RedisTemplate with raw byte arrays by setting the enableDefaultSerializer property to false. Note that the template requires all keys to be non-null. However, values can be null as long as the underlying serializer accepts them. Read the Javadoc of each serializer for more information.

对于需要特定模板视图的情况,将视图声明为依赖项并注入模板。容器会自动执行转换,消除 opsFor[X] 调用,如下面的示例所示:

For cases where you need a certain template view, declare the view as a dependency and inject the template. The container automatically performs the conversion, eliminating the opsFor[X] calls, as shown in the following example:

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 和代码中都使用了相同的编码)。以下清单显示了一个示例:

Since it is quite common for the keys and values stored in Redis to be java.lang.String, the Redis modules provides two extensions to RedisConnection and RedisTemplate, respectively the StringRedisConnection (and its DefaultStringRedisConnection implementation) and StringRedisTemplate as a convenient one-stop solution for intensive String operations. In addition to being bound to String keys, the template and the connection use the StringRedisSerializer underneath, which means the stored keys and values are human-readable (assuming the same encoding is used both in Redis and your code). The following listings show an example:

  • 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 接口:

As with the other Spring templates, RedisTemplate and StringRedisTemplate let you talk directly to Redis through the RedisCallback interface. This feature gives complete control to you, as it talks directly to the RedisConnection. Note that the callback receives an instance of StringRedisConnection when a StringRedisTemplate is used. The following example shows how to use the RedisCallback interface:

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 本身支持各种类型,但大多数情况下,这些类型指代的是数据的存储方式,而不是它表示的内容。用户要自己决定是将信息转换为字符串还是其他任何对象。

From the framework perspective, the data stored in Redis is only bytes. While Redis itself supports various types, for the most part, these refer to the way the data is stored rather than what it represents. It is up to the user to decide whether the information gets translated into strings or any other objects.

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

In Spring Data, the conversion between the user (custom) types and raw data (and vice-versa) is handled by Spring Data Redis in the org.springframework.data.redis.serializer package.

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

This package contains two types of serializers that, as the name implies, take care of the serialization process:

  • Two-way serializers based on RedisSerializer.

  • Element readers and writers that use RedisElementReader and RedisElementWriter.

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

The main difference between these variants is that RedisSerializer primarily serializes to byte[] while readers and writers use ByteBuffer.

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

Multiple implementations are available (including two that have been already mentioned in this documentation):

  • JdkSerializationRedisSerializer, which is used by default for RedisCache and RedisTemplate.

  • the StringRedisSerializer.

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

However, one can use OxmSerializer for Object/XML mapping through Spring {spring-framework-docs}/data-access.html#oxm[OXM] support or Jackson2JsonRedisSerializer or GenericJackson2JsonRedisSerializer for storing data in JSON format.

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

Do note that the storage format is not limited only to values. It can be used for keys, values, or hashes without any restrictions.

默认情况下,RedisCacheRedisTemplate 被配置为使用 Java 本机序列化。Java 本机序列化允许运行远程代码,原因是注入未经验证的字节代码的有效负载会利用易受攻击的库和类。处理输入时,可能会导致在反序列化步骤中在应用程序中运行不需要的代码。因此,不要在不受信任的环境中使用序列化。通常,我们强烈建议使用任何其他消息格式(例如 JSON)。

By default, RedisCache and RedisTemplate are configured to use Java native serialization. Java native serialization is known for allowing the running of remote code caused by payloads that exploit vulnerable libraries and classes injecting unverified bytecode. Manipulated input could lead to unwanted code being run in the application during the deserialization step. As a consequence, do not use serialization in untrusted environments. In general, we strongly recommend any other message format (such as JSON) instead.

如果您担心由于 Java 序列化而引起的安全性漏洞,请考虑核心 JVM 级别的一般用途序列化过滤机制:

If you are concerned about security vulnerabilities due to Java serialization, consider the general-purpose serialization filter mechanism at the core JVM level: