Working with Objects through RedisTemplate
大多数用户都可能使用 RedisTemplate
及其相应的包 org.springframework.data.redis.core
或其响应式变体 ReactiveRedisTemplate
。模板实际上是 Redis 模块的核心类,因为它具有丰富的功能集。模板为 Redis 交互提供了高级抽象。虽然 [Reactive]RedisConnection
提供了接受和返回二进制值(byte
数组)的底层方法,但模板负责序列化和连接管理,从而使用户不必处理此类细节。
RedisTemplate
类实现了 RedisOperations
接口,其响应变体 ReactiveRedisTemplate
实现了 ReactiveRedisOperations
。
通过“ |
此外,模板提供了操作视图(遵循 Redis 命令 reference 中的分组),为针对特定类型或特定键(通过 KeyBound
接口)工作提供了丰富的泛化接口,如下表所示:
.Operational views
- Imperative
-
Interface Description Key Type Operations
GeoOperations
Redis 地理空间操作,例如
GEOADD
、GEORADIUS
……HashOperations
Redis hash operations
HyperLogLogOperations
类似
PFADD
、PFCOUNT
… 的 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
像
GEOADD
、GEORADIUS
等 Redis 地理空间操作ReactiveHashOperations
Redis hash operations
ReactiveHyperLogLogOperations
像 (
PFADD
、PFCOUNT
等的 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]
调用,如下面的示例所示:
-
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>
[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 模块为 RedisConnection
和 RedisTemplate
分别提供了两个扩展,即 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 模板一样,RedisTemplate
和 StringRedisTemplate
允许你通过 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
的双向序列化器。 -
使用
RedisElementReader
和RedisElementWriter
的元素读取器和写入器。
这些变体之间的主要区别在于 RedisSerializer
主要序列化为 byte[]
,而读取器和写入器使用 ByteBuffer
。
有多种实现可用(包括本文档中已提及的两种):
-
JdkSerializationRedisSerializer
,默认情况下用于RedisCache
和RedisTemplate
。 -
the
StringRedisSerializer
.
但是,可以使用 OxmSerializer
进行对象/XML 映射,可以通过 Spring {spring-framework-docs}/data-access.html#oxm[OXM] 支持或使用 Jackson2JsonRedisSerializer
或 GenericJackson2JsonRedisSerializer
以 JSON 格式存储数据。
请注意,存储格式不限于值。它可以毫无限制地用于键、值或哈希。
默认情况下,RedisCache
和 RedisTemplate
被配置为使用 Java 本机序列化。Java 本机序列化允许运行远程代码,原因是注入未经验证的字节代码的有效负载会利用易受攻击的库和类。处理输入时,可能会导致在反序列化步骤中在应用程序中运行不需要的代码。因此,不要在不受信任的环境中使用序列化。通常,我们强烈建议使用任何其他消息格式(例如 JSON)。
如果您担心由于 Java 序列化而引起的安全性漏洞,请考虑核心 JVM 级别的一般用途序列化过滤机制: