springboot2默认已经使用了lettuce-core,没有使用jedis和Redisson,springboot1使用的是jedis。
我使用的springboot版本是2.6.14。(对应的lettuce版本为6.1.10.RELEASE,对应jedis版本为3.7.1)
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.1.10.RELEASE</version>
</dependency>
<!-- 或者 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.1</version>
</dependency>
添加依赖
<!--redis-->
<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>
spring和redis这建立连接不管你使用那种客户端都只需要使用一组Spring Data Redis API(在所有连接器上都表现一致):org.springframework.Data.Redis.connection包及其RedisConnection和RedisConnectionFactory接口,用于处理和检索Redis的活动连接。
配置Lettuce连接器(Configuring the Lettuce Connector)
@Configuration
class AppConfig {
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(new RedisStandaloneConfiguration("server", 6379));
}
}
配置jedis连接器(Configuring the Jedis Connector)
Jedis is a community-driven connector supported by the Spring Data Redis module through the org.springframework.data.redis.connection.jedis
package.
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.1</version>
</dependency>
在最简单的形式中,Jedis配置如下所示:
@Configuration
class AppConfig {
@Bean
public JedisConnectionFactory redisConnectionFactory() {
return new JedisConnectionFactory();
}
}
但是,对于生产使用,您可能需要调整主机或密码等设置,如以下示例所示:
@Configuration
class RedisConfiguration {
@Bean
public JedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration("server", 6379);
return new JedisConnectionFactory(config);
}
}
Redis主/副本设置 — 没有自动故障切换(有关自动故障切换,请参阅:Sentinel) — 不仅允许数据安全地存储在更多的节点上。它还允许使用Lettuce从复制副本读取数据,同时将写入操作推送给主控。您可以使用LettuceClientConfiguration设置要使用的读/写策略,如下例所示:
@Configuration
class WriteToMasterReadFromReplicaConfiguration {
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
.readFrom(REPLICA_PREFERRED)
.build();
RedisStandaloneConfiguration serverConfig = new RedisStandaloneConfiguration("server", 6379);
return new LettuceConnectionFactory(serverConfig, clientConfig);
}
}
注:
对于通过INFO命令报告非公共地址的环境(例如,使用AWS时),请使用RedisStaticMasterReplicaConfiguration而不是RedisStandaloneConfiguration。请注意,RedisStaticMasterReplicaConfiguration不支持Pub/Sub,因为缺少跨各个服务器的Pub/Sub消息传播。
Redis哨兵模式支持(Redis Sentinel Support)
/**
* Jedis
*/
@Bean
public RedisConnectionFactory jedisConnectionFactory() {
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
.master("mymaster")
.sentinel("127.0.0.1", 26379)
.sentinel("127.0.0.1", 26380);
return new JedisConnectionFactory(sentinelConfig);
}
/**
* Lettuce
*/
@Bean
public RedisConnectionFactory lettuceConnectionFactory() {
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
.master("mymaster")
.sentinel("127.0.0.1", 26379)
.sentinel("127.0.0.1", 26380);
return new LettuceConnectionFactory(sentinelConfig);
}
RedisStinelConfiguration也可以用PropertySource来定义,它允许您设置以下属性:
配置属性
spring.dis.setinel.master:主节点的名称。
spring.redis.setinel.nodes:以逗号分隔的主机:端口对列表。
spring.redis.setinel.password:使用redis sentinel进行身份验证时应用的密码
有时,需要与其中一名哨兵直接互动。使用RedisConnectionFactory.getSentinelConnection()或RedisConnection.getSentinelCommands()可以访问配置的第一个活动Sentinel。
通过RedisTemplate处理对象
大多数用户可能会使用RedisTemplate及其相应的包org.springframework.data.redis.core。由于其丰富的功能集,该模板实际上是redis模块的中心类。该模板为Redis交互提供了高级抽象。虽然RedisConnection提供了接受和返回二进制值(字节数组)的低级方法,但该模板负责序列化和连接管理,使用户无需处理这些细节。
此外,该模板提供了操作视图(遵循Redis命令引用中的分组),这些视图提供了丰富的通用接口,用于(通过KeyBound接口)对特定类型或特定密钥进行操作,如下表所示:
配置后,模板是线程安全的,可以在多个实例中重用。
RedisTemplate的大部分操作都使用基于Java的序列化程序。这意味着模板编写或读取的任何对象都是通过Java序列化和反序列化的。您可以更改模板上的序列化机制,Redis模块提供了几个实现,这些实现在org.springframework.data.Redis.serializer包中提供。有关详细信息,请参阅序列化程序。您还可以将任何序列化程序设置为null,并通过将enableDefaultSerializer属性设置为false将RedisTemplate与原始字节数组一起使用。请注意,该模板要求所有键都为非null。但是,只要底层序列化程序接受值,它们就可以为null。有关详细信息,请阅读每个序列化程序的Javadoc。
对于需要某个模板视图的情况,请将该视图声明为依赖项并注入模板。容器会自动执行转换,从而消除opsFor[X]调用,如下例所示:
<?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="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:use-pool="true"/>
<!-- redis template definition -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref="jedisConnectionFactory"/>
...
</beans>
public class Example {
// inject the actual template
@Autowired
private RedisTemplate<String, String> template;
// 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());
}
}
以字符串为中心的便利类(StringRedistTemplate)
由于Redis中存储的键和值是java.lang.String是很常见的,Redis模块为RedisConnection和RedisTemplate提供了两个扩展,分别是StringRedisConnect(及其DefaultStringRedisConfiguration实现)和StringRedistTemplate,作为密集String操作的一站式解决方案。除了绑定到String键之外,模板和连接还使用下面的StringRedisSerializer,这意味着存储的键和值是可读的(假设Redis和代码中使用相同的编码)。以下列表显示了一个示例:
<?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="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:use-pool="true"/>
<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate" p:connection-factory-ref="jedisConnectionFactory"/>
...
</beans>
public class Example {
@Autowired
private StringRedisTemplate redisTemplate;
public void addLink(String userId, URL url) {
redisTemplate.opsForList().leftPush(userId, url.toExternalForm());
}
}
与其他Spring模板一样,RedisTemplate和StringRedisTemplate可以通过RedisCallback接口直接与Redis对话。此功能可以完全控制您,因为它可以直接与RedisConnection对话。请注意,当使用StringRedisTemplate时,回调将接收StringRedisConnection的实例。下面的例子展示了如何使用RedisCallback接口:
public void useCallback() {
redisTemplate.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中,用户(自定义)类型和原始数据之间的转换(反之亦然)由org.springframework.Data.Redis.serializer包中的Redis处理。
该包包含两种类型的序列化程序,顾名思义,它们负责序列化过程:
基于RedisSerializer的双向序列化程序。
使用RedisElementReader和RedisElementWriter的元素读取器和写入程序。
这些变体之间的主要区别在于RedisSerializer主要序列化到byte[],而读写器使用ByteBuffer。
有多种实现可用(包括本文档中已经提到的两种):
1、JdkSerializationRedisSerializer,默认用于RedisCache和RedisTemplate。
2、StringRedisSerializer。
但是,可以通过Spring OXM支持使用OxmSerializer进行Object/XML映射,或者使用Jackson2JsonRedisSerializer或GenericJackson2J sonRedisSserializer以JSON格式存储数据。
请注意,存储格式不仅限于值。它可以用于键、值或哈希,没有任何限制。
默认情况下,RedisCache和RedisTemplate配置为使用Java本机序列化。众所周知,Java本机序列化允许运行由有效负载引起的远程代码,这些有效负载利用易受攻0击的库和类注入未经验证的字节码。操作输入可能导致在反序列化步骤期间在应用程序中运行不需要的代码。因此,不要在不受信任的环境中使用序列化。通常,我们强烈建议使用任何其他消息格式(如JSON)。
Hash mapping(哈希映射)
可以使用Redis中的各种数据结构来存储数据。Jackson2JsonRedisSerializer可以转换JSON格式的对象。理想情况下,JSON可以通过使用纯键存储为值。通过使用Redis散列,可以实现更复杂的结构化对象映射。Spring Data Redis提供了各种将数据映射到哈希的策略(取决于用例):
1、直接映射,使用HashOperations和序列化程序进行。
2、使用Redis存储库。
3、使用HashMapper和HashOperations。
Hash Mappers
Hash mappers 是映射对象到map<K,V>和返回的转换器。HashMapper用于Redis哈希。
有多种实施方式可用:
BeanUtilsHashMapper
using Spring’s BeanUtils.ObjectHashMapper
using Object-to-Hash Mapping.- Jackson2HashMapper using FasterXML Jackson.
以下示例显示了一种实现哈希映射的方法:
public class Person {
String firstname;
String lastname;
// …
}
public class HashMapping {
@Autowired
HashOperations<String, byte[], byte[]> hashOperations;
HashMapper<Object, byte[], byte[]> mapper = new ObjectHashMapper();
public void writeHash(String key, Person person) {
Map<byte[], byte[]> mappedHash = mapper.toHash(person);
hashOperations.putAll(key, mappedHash);
}
public Person loadHash(String key) {
Map<byte[], byte[]> loadedHash = hashOperations.entries("key");
return (Person) mapper.fromHash(loadedHash);
}
}
Jackson2HashMapper
Jackson2HashMapper通过使用FasterXMLJackson为域对象提供Redis哈希映射。Jackson2HashMapper可以将顶级属性映射为哈希字段名,还可以选择展平结构。简单类型映射到简单值。复杂类型(嵌套对象、集合、映射等)表示为嵌套JSON。
扁平化为所有嵌套属性创建单独的哈希条目,并尽可能将复杂类型解析为简单类型。
考虑以下类及其包含的数据结构:
public class Person {
String firstname;
String lastname;
Address address;
Date date;
LocalDateTime localDateTime;
}
public class Address {
String city;
String country;
}
The following table shows how the data in the preceding class would appear in normal mapping:
The following table shows how the data in the preceding class would appear in flat mapping:
扁平化要求所有属性名称不干扰JSON路径。使用展开时,不支持在映射键中使用点或括号或将其用作特性名称。生成的哈希无法映射回对象。
java.util.Date和java.util.Calendar用毫秒表示。如果jackson-datatype-jsr310在类路径上,JSR-310日期/时间类型将序列化为它们的toString形式。
Redis集群模式(Redis Cluster)
启用Redis群集
集群支持基于与非集群通信相同的构建块。RedisClusterConnection是RedisConnection的扩展,它处理与Redis集群的通信,并将错误转换为Spring DAO异常层次结构。RedisClusterConnection实例是使用RedisConnectionFactory创建的,必须使用关联的RedisCluster配置进行设置,如下例所示:
@Component
@ConfigurationProperties(prefix = "spring.redis.cluster")
public class ClusterConfigurationProperties {
/*
* spring.redis.cluster.nodes[0] = 127.0.0.1:7379
* spring.redis.cluster.nodes[1] = 127.0.0.1:7380
* ...
*/
List<String> nodes;
/**
* Get initial collection of known cluster nodes in format {@code host:port}.
*
* @return
*/
public List<String> getNodes() {
return nodes;
}
public void setNodes(List<String> nodes) {
this.nodes = nodes;
}
}
@Configuration
public class AppConfig {
/**
* Type safe representation of application.properties
*/
@Autowired ClusterConfigurationProperties clusterProperties;
public @Bean RedisConnectionFactory connectionFactory() {
return new JedisConnectionFactory(
new RedisClusterConfiguration(clusterProperties.getNodes()));
}
}
RedisClusterConfiguration也可以通过PropertySource定义,并具有以下属性:
配置属性
spring.redis.cluster.nodes:host:port对的逗号分隔列表。
spring.redis.cluster.max-redirects:允许的群集重定向数。
使用Redis群集连接
如前所述,Redis集群的行为与单节点Redis甚至Sentinel监控的主副本环境不同。这是因为自动分片将一个密钥映射到16384个槽中的一个,这些槽分布在节点之间。因此,涉及多个密钥的命令必须断言所有密钥映射到完全相同的插槽,以避免跨插槽错误。单个集群节点仅提供一组专用密钥。针对某个特定服务器发出的命令只返回该服务器提供的密钥的结果。作为一个简单的例子,可以考虑KEYS命令。当发布到集群环境中的服务器时,它只返回请求发送到的节点提供的密钥,而不一定返回集群中的所有密钥。因此,要获得集群环境中的所有密钥,必须从所有已知的主节点读取密钥。
虽然特定密钥到相应插槽服务节点的重定向由驱动程序库处理,但RedisClusterConnection涵盖了更高级别的功能,如跨节点收集信息或向群集中的所有节点发送命令。根据前面的keys示例,这意味着keys(pattern)方法会拾取集群中的每个主节点,并在每个主节点上同时运行keys命令,同时拾取结果并返回累积的密钥集。只请求单个节点的密钥RedisClusterConnection为这些方法(例如,密钥(node,pattern))提供了重载。
RedisClusterNode可以从RedisCluster Connection.clusterGetNodes获得,也可以使用主机和端口或节点Id来构建。
以下示例显示了在集群中运行的一组命令:
示例6。在集群中运行命令的示例
当所有密钥映射到同一插槽时,本机驱动程序库会自动提供跨插槽请求,例如MGET。然而,一旦情况并非如此,RedisClusterConnection就会对插槽服务节点运行多个并行GET命令,并再次返回累积结果。这种方法的性能不如单槽方法,因此应谨慎使用。如果有疑问,可以考虑通过在花括号中提供前缀将密钥固定到同一个插槽,例如{myprefix}.thing1和{myprefix}.thing2,它们都将映射到同一插槽编号。以下示例显示跨插槽请求处理:
前面的示例演示了Spring Data Redis所遵循的一般策略。请注意,有些操作可能需要将大量数据加载到内存中才能计算所需的命令。此外,并非所有跨槽请求都可以安全地移植到多个单槽请求,如果误用,则会出现错误(例如,PFCOUNT)。
使用RedisTemplate和ClusterOperations
使用任何JSON RedisSerializer设置RedisTemplate#keySerializer时要小心,因为更改JSON结构会直接影响哈希槽计算。
RedisTemplate通过ClusterOperations接口提供对集群特定操作的访问,该接口可以从RedisTemplate.opsForCluster()获得。这使您可以在集群中的单个节点上显式运行命令,同时保留为模板配置的序列化和反序列化功能。它还提供管理命令(如CLUSTER MEET)或更高级的操作(例如,重新发布)。
以下示例显示如何使用RedisTemplate访问RedisClusterConnection: