tulip notes
首页
  • 学习笔记

    • 《Vue》
  • 踩坑日记

    • JavaScript
  • MQ
  • Nginx
  • IdentityServer
  • Redis
  • Linux
  • Java
  • SpringBoot
  • SpringCloud
  • MySql
  • docker
  • 算法与设计模式
  • 踩坑与提升
  • Git
  • GitHub技巧
  • Mac
  • 网络
  • 项目构建合集
  • 一些技巧
  • 面试
  • 一些杂货
  • 友情链接
  • 项目发布
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Star-Lord

希望一天成为大师的学徒
首页
  • 学习笔记

    • 《Vue》
  • 踩坑日记

    • JavaScript
  • MQ
  • Nginx
  • IdentityServer
  • Redis
  • Linux
  • Java
  • SpringBoot
  • SpringCloud
  • MySql
  • docker
  • 算法与设计模式
  • 踩坑与提升
  • Git
  • GitHub技巧
  • Mac
  • 网络
  • 项目构建合集
  • 一些技巧
  • 面试
  • 一些杂货
  • 友情链接
  • 项目发布
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 探索SpringBoot

  • 常用功能实现

    • SpringBoot常用功能实现_1
    • SpringBoot中拦截器与日志
    • 多环境配置与数据绑定
    • 异步方法(线程池)的实现
    • controller参数接收
    • SpringBoot中关于日志的更好使用
    • 异常捕获的一些细节
    • 时间跟其他数据的序列化
    • 面向切面跟自定义注解的结合
    • 集成Redis及注意事项
      • 引入依赖
      • 配置链接
      • 使用
        • 自定义 RedisTemplate
        • 为什么要序列化
        • 核心原因
        • 不序列化的问题
        • RedisTemplate 支持哪些序列化方式?
        • StringRedisSerializer
        • GenericJackson2JsonRedisSerializer
        • Hash 结构的序列化
        • 扩展-FastJson进行序列化
        • 自定义连接池配置
  • Security认证授权

  • 扩展

  • 实战与注意事项

  • 其它

  • 《SpringBoot》笔记
  • 常用功能实现
EffectTang
2025-06-08
目录

集成Redis及注意事项

# 集成Redis及注意事项

redis作为一个常用的中间件,学会在SpringBoot应用中使用它,是很重要的,下面就介绍如何引入和使用,以及一些注意事项。

# 引入依赖

<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>
1
2
3
4
5
6
7
8
9

关于如何使用Jedis、Lettuce这里就不展开了,在介绍Redis的客户端那一篇中有详细说明。

  • spring-boot-starter-data-redis:包含 Spring Data Redis 的核心功能,默认使用 Lettuce。
  • commons-pool2:用于 Lettuce 连接池管理。

# 配置链接

在 application.yml 中配置 Redis 服务器信息和连接池参数:

spring:
  data:
    redis:
      host: 127.0.0.1
      port: 6379
      password: 123456
      database: 0
      timeout: 5000ms  # 连接超时时间
      lettuce:
        pool:
          max-active: 10      # 最大连接数(推荐:CPU * 2 + 2)
          max-idle: 8         # 最大空闲连接数(推荐:CPU * 2)
          min-idle: 2         # 最小空闲连接数
          max-wait: 2000ms    # 获取连接的最大等待时间
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 使用

# 自定义 RedisTemplate

Spring Data Redis 提供了 RedisTemplate 和 StringRedisTemplate,但默认的 RedisTemplate 使用 JDK 序列化(不推荐),需要自定义配置以支持对象存储。

下列为一个参考示例:

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        // 设置 Key 和 HashKey 的序列化方式为 String
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());

        // 设置 Value 和 HashValue 的序列化方式为 JSON
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());

        return template;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

默认 JdkSerializationRedisSerializer 会产生二进制乱码,推荐 JSON 序列化。

  • GenericJackson2JsonRedisSerializer:将 Java 对象序列化为 JSON,可读性强且支持跨语言兼容。
  • StringRedisSerializer:用于字符串类型的 Key。
  • JdkSerializationRedisSerializer:不推荐使用(生成的 Key 是乱码)。

# 为什么要序列化

为什么要对 RedisTemplate 进行序列化?

Redis 是一个键值数据库,它只能存储 字节数组(byte[])。Java 对象(如 POJO、List、Map 等)无法直接存储到 Redis 中,必须通过 序列化器(Serializer) 将对象转换为字节数组,再反向操作将字节数组还原为 Java 对象。

# 核心原因

  1. 数据格式兼容性:
    • Redis 的 Key 和 Value 都是字节数组,Java 对象必须通过序列化器转换为字节数组才能存储。
  2. 跨语言支持:
    • 如果 Redis 需要与其他语言(如 Python、Node.js)交互,使用 JSON 格式序列化可以保证数据可读性和兼容性。
  3. 调试与监控:
    • 使用可读的序列化格式(如 JSON)可以方便地通过 Redis 客户端(如 redis-cli)查看存储的数据。

# 不序列化的问题

Spring Data Redis 默认使用 JDK 序列化器,但存在以下问题:

  • 可读性差:存储的数据是二进制格式,通过 redis-cli 查看时会显示乱码。
"rO0ABXNyABFqYXZheC5sZXZlbC5UZXN0TGV2ZWwK..."
1
  • 跨语言不兼容:其他语言无法解析 JDK 序列化的数据。
  • 类版本问题:如果修改了 Java 类的结构(如增删字段),反序列化会失败。

存储复杂对象的混乱

如果直接存储对象(如 User user = new User("Alice", 25);),未配置序列化器会导致:

  • 存储的 Key 和 Value 是乱码。
  • 无法通过 Redis 客户端直接查看或调试数据。

性能问题

  • JDK 序列化器的性能较低,且生成的字节数组较大,占用更多内存和网络带宽。

# RedisTemplate 支持哪些序列化方式?

# StringRedisSerializer

  • 用途:序列化字符串(String)类型的数据。
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
1
2

# GenericJackson2JsonRedisSerializer

  • 用途:序列化复杂对象(POJO、List、Map 等)为 JSON 格式。
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
1

# Hash 结构的序列化

  • Hash Key/Value 的独立配置:
    • 可以分别为 Hash 的 Key 和 Value 配置不同的序列化器。
    • 例如:Hash 的 Key 使用 StringRedisSerializer,Value 使用 GenericJackson2JsonRedisSerializer。
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
1
2

最后总结下:

问题 解决方案
为什么要序列化? Redis 只能存储字节数组,Java 对象需通过序列化器转换。
不序列化有什么问题? 默认 JDK 序列化器导致数据不可读、跨语言不兼容、类版本问题。
常见序列化方式有哪些? StringRedisSerializer、GenericJackson2JsonRedisSerializer、Protobuf 等。
每种数据类型都需要序列化吗? 简单类型(String、Number)无需序列化,复杂类型(POJO、Hash)必须配置。

# 扩展-FastJson进行序列化

除了使用jackson进行序列化,还可以使用FastJson进行序列化。

使用 FastJson 作为 RedisTemplate 的序列化器,替代 GenericJackson2JsonRedisSerializer(基于 Jackson)。以下是具体实现方式和注意事项:

  • 引入依赖
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.83</version> <!-- 使用最新稳定版本 -->
</dependency>
1
2
3
4
5
  • 自定义 FastJsonRedisSerializer

创建自定义的 Redis 序列化器类,实现 RedisSerializer 接口:

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import java.nio.charset.StandardCharsets;

public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {

    private final Class<T> clazz;

    public FastJsonRedisSerializer(Class<T> clazz) {
        this.clazz = clazz;
    }

    @Override
    public byte[] serialize(T value) throws SerializationException {
        if (value == null) {
            return new byte[0];
        }
        // 将对象转换为 JSON 字符串,并写入类名(可选)
        String json = JSON.toJSONString(value, 
            SerializerFeature.WriteClassName); // 写入类名,用于反序列化
        return json.getBytes(StandardCharsets.UTF_8);
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        String json = new String(bytes, StandardCharsets.UTF_8);
        return JSON.parseObject(json, clazz);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  • 配置 RedisTemplate

在 Spring Boot 配置类中,覆盖默认的 RedisTemplate 配置:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        // Key 和 Hash Key 使用 StringRedisSerializer
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());

        // Value 和 Hash Value 使用 FastJsonRedisSerializer
        template.setValueSerializer(new FastJsonRedisSerializer<>(Object.class));
        template.setHashValueSerializer(new FastJsonRedisSerializer<>(Object.class));

        return template;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

通过自定义 FastJsonRedisSerializer,可以灵活控制序列化行为(如类名、循环引用等)。

在配置时注意泛型类型匹配和编码方式(推荐 UTF-8),以确保数据正确存储和读取。

# 自定义连接池配置

Lettuce 的连接池基于 LettucePoolingClientConfiguration,可通过以下方式进一步优化:(可选)

@Bean
public RedisConnectionFactory redisConnectionFactory() {
    RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
    config.setHostName("127.0.0.1");
    config.setPort(6379);
    config.setPassword("123456");

    LettucePoolingClientConfiguration poolingConfig = LettucePoolingClientConfiguration.builder()
        .poolConfig(new GenericObjectPoolConfig<>())
        .commandTimeout(Duration.ofSeconds(5))
        .build();

    return new LettuceConnectionFactory(config, poolingConfig);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
上次更新: 2025/06/08, 15:47:55
面向切面跟自定义注解的结合
认证授权与SpringSecurity_概念篇

← 面向切面跟自定义注解的结合 认证授权与SpringSecurity_概念篇→

最近更新
01
Vue项目发布
06-04
02
MinIo跟对象存储服务
05-25
03
面向切面跟自定义注解的结合
05-22
更多文章>
Theme by Vdoing | Copyright © 2023-2025 EffectTang
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式