通过`RedisTemplate`使用对象

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

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

引用`[Reactive]RedisTemplate`实例操作的首选方法是通过`[Reactive]RedisOperations`接口。

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

操作视图
  • 命令式

  • 响应式

接口 描述

键类型操作

GeoOperations

Redis地理空间操作,例如`GEOADD`、`GEORADIUS`……

HashOperations

Redis哈希操作

HyperLogLogOperations

Redis HyperLogLog操作,例如`PFADD`、`PFCOUNT`……

ListOperations

Redis列表操作

SetOperations

Redis集合操作

ValueOperations

Redis字符串(或值)操作

ZSetOperations

Redis zset(或有序集合)操作

键绑定操作

BoundGeoOperations

Redis键绑定地理空间操作

BoundHashOperations

Redis哈希键绑定操作

BoundKeyOperations

Redis键绑定操作

BoundListOperations

Redis列表键绑定操作

BoundSetOperations

Redis集合键绑定操作

BoundValueOperations

Redis字符串(或值)键绑定操作

BoundZSetOperations

Redis zset(或有序集合)键绑定操作

接口 描述

键类型操作

ReactiveGeoOperations

Redis地理空间操作(例如`GEOADD`、`GEORADIUS`等)

ReactiveHashOperations

Redis哈希操作

ReactiveHyperLogLogOperations

Redis HyperLogLog操作(例如`PFADD`、`PFCOUNT`等)

ReactiveListOperations

Redis列表操作

ReactiveSetOperations

Redis集合操作

ReactiveValueOperations

Redis字符串(或值)操作

ReactiveZSetOperations

Redis zset(或有序集合)操作

配置完成后,模板是线程安全的,可以在多个实例中重用。

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

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

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

配置模板API
  • Java命令式

  • Java响应式

  • 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>
使用`[Reactive]RedisTemplate`将项目推入列表
  • 命令式

  • 响应式

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());
  }
}

以字符串为中心的便捷类

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

  • Java命令式

  • Java响应式

  • 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>
  • 命令式

  • 响应式

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");
    }
   });
}

序列化器

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

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

此包包含两种类型的序列化器,顾名思义,它们负责序列化过程。

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

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

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

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

但是,可以使用OxmSerializer通过Spring OXM支持进行对象/XML映射,或者使用Jackson2JsonRedisSerializerGenericJackson2JsonRedisSerializerJSON格式存储数据。

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

默认情况下,RedisCacheRedisTemplate配置为使用Java原生序列化。Java原生序列化已知允许运行远程代码,这是由利用易受攻击的库和类(注入未经验证的字节码)的有效负载引起的。被操纵的输入可能导致在反序列化步骤期间在应用程序中运行不需要的代码。因此,请勿在不受信任的环境中使用序列化。一般来说,我们强烈建议使用任何其他消息格式(例如JSON)。

如果您担心Java序列化造成的安全漏洞,请考虑核心JVM级别的通用序列化过滤器机制。