(四十)SpringBoot 集成 Redis

摘要

  • 本文介绍 SpringBoot 集成 Redis 的方法
  • 本文基于redis-7.4.7springboot-3.5.8
  • Redis官网:https://redis.io/

引入依赖

  • pom.xml中引入依赖
xml 复制代码
<dependencyManagement>
   <dependencies>
      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>3.5.8</version>
            <type>pom</type>
            <scope>import</scope>
      </dependency>
   </dependencies>
</dependencyManagement>

<dependencies>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
   </dependency>
   <!-- redis 连接池 -->
   <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-pool2</artifactId>
   </dependency>
</dependencies>

配置 application.yml

单机模式

yml 复制代码
spring:
  data:
    redis:
      host: 127.0.0.1
      port: 6379
      database: 0
      username: admin
      password: redis123
      timeout: 5s
      connectTimeout: 3s
      clientName: demo-service
      lettuce:
        shutdown-timeout: 100ms
        pool:
          max-active: 64
          max-idle: 32
          min-idle: 16
          max-wait: 2s
          time-between-eviction-runs: 30s
  • 基础连接配置项
配置项 示例值 含义 默认值 生产建议
spring.data.redis.host localhost Redis 服务地址(IP / 域名) localhost 生产使用内网 IP / 域名
spring.data.redis.port 6379 Redis 服务端口 6379 一般无需修改
spring.data.redis.username admin Redis ACL 用户名(Redis 6+) (空) 未启用 ACL 可不配置
spring.data.redis.password 123456 Redis 访问密码 (空) 生产必须配置
spring.data.redis.database 0 逻辑数据库索引(0--15) 0 Cluster 模式无效
spring.data.redis.timeout 3s Redis 命令执行超时 60s(依版本) 建议 2--5s
spring.data.redis.connect-timeout 3s TCP 建连超时 OS 默认 建议 1--5s
spring.data.redis.client-name my-redis-client 客户端标识,用于运维定位 (空) 强烈建议配置
  • 连接池配置(Lettuce Pool)
配置项 示例值 含义 默认值 生产建议
spring.data.redis.lettuce.pool.max-active 8 连接池最大连接数(使用中 + 空闲) 8 CPU × 2~4 或压测评估
spring.data.redis.lettuce.pool.max-wait 2s 连接耗尽时等待时间 -1(无限等待) 必须设置,1--3s
spring.data.redis.lettuce.pool.max-idle 8 最大空闲连接数 8 max-active × 30%~50%
spring.data.redis.lettuce.pool.min-idle 0 最小空闲连接数 0 ≥ max-active × 25%
spring.data.redis.lettuce.pool.time-between-eviction-runs 60s 空闲连接检测周期 -1(不启用) 30--60s
  • Lettuce 客户端运行参数
配置项 示例值 含义 默认值 生产建议
spring.data.redis.lettuce.shutdown-timeout 100ms 应用关闭时等待连接释放时间 100ms 一般无需修改

sentinel 模式

yml 复制代码
spring:
  data:
    redis:
      database: 0
      username: admin
      password: redis123
      timeout: 5s
      connectTimeout: 3s
      clientName: demo-service
      sentinel:
        master: mymaster
        nodes:
          - 10.0.0.10:26379
          - 10.0.0.11:26379
          - 10.0.0.12:26379
      lettuce:
        shutdown-timeout: 100ms
        pool:
          max-active: 64
          max-idle: 32
          min-idle: 16
          max-wait: 2s
          time-between-eviction-runs: 30s
  • 哨兵模式配置项
配置项 示例值 含义 是否必填 说明
spring.data.redis.sentinel.master mymaster Sentinel 监控的 Master 名称 必须与 Sentinel monitor 名称完全一致
spring.data.redis.sentinel.nodes 10.0.0.10:26379,10.0.0.11:26379,10.0.0.12:26379 Sentinel 节点列表 至少配置 2--3 个 Sentinel,提升可用性
spring.data.redis.sentinel.username (空) Sentinel 的认证用户名 如果启用 ACL,则必填
spring.data.redis.sentinel.password (空) Sentinel 的认证密码 如果启用 ACL,则必填

cluster 模式

yml 复制代码
spring:
  data:
    redis:
      username: admin
      password: redis123
      timeout: 5s
      connectTimeout: 3s
      clientName: order-service
      cluster:
        nodes:
          - 192.168.1.10:6379
          - 192.168.1.11:6379
          - 192.168.1.12:6379
      lettuce:
        shutdown-timeout: 100ms
        cluster:
          refresh:
            adaptive: true
            period: 10s
        pool:
          max-active: 64
          max-idle: 32
          min-idle: 16
          max-wait: 2s
          time-between-eviction-runs: 30s
  • 注意
bash 复制代码
集群模式下,不能配置 `spring.data.redis.database`,因为集群只能使用默认数据库索引 0
  • 集群模式配置项
配置项 示例值 含义 是否必填 默认值 生产建议
spring.data.redis.cluster.nodes 192.168.1.10:6379,... Redis Cluster 节点地址列表 (空) 至少配置 3 个节点
  • Cluster 拓扑自动刷新配置,用于解决集群拓扑变化时 Client 无法自动感知
配置项 示例值 含义 默认值 是否推荐
adaptive true 开启 事件驱动拓扑刷新 false ✅ 必须
period 10s 开启 定时拓扑刷新周期 关闭 ✅ 必须

SpringBoot 配置类

封装 RedisTemplate

java 复制代码
package com.example.config;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
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.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public ObjectMapper redisObjectMapper() {
        return JsonMapper.builder()
                .addModule(new JavaTimeModule())
                .serializationInclusion(JsonInclude.Include.NON_NULL)
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .build();
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(
            RedisConnectionFactory connectionFactory,
            ObjectMapper objectMapper) {

        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        // --- Key 序列化 ---
        StringRedisSerializer stringSerializer = new StringRedisSerializer();

        // --- Value 序列化 ---
        // 使用 Jackson JSON,避免 JDK 序列化性能与安全问题
        GenericJackson2JsonRedisSerializer jsonSerializer =
                new GenericJackson2JsonRedisSerializer(objectMapper);

        // Key
        template.setKeySerializer(stringSerializer);
        template.setHashKeySerializer(stringSerializer);

        // Value
        template.setValueSerializer(jsonSerializer);
        template.setHashValueSerializer(jsonSerializer);

        template.afterPropertiesSet();
        return template;
    }
}

开启注解式缓存

java 复制代码
package com.example.config;


import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

@Configuration
@AutoConfigureAfter(value = RedisConfig.class)
//注入redis分组配置属性:ttlmap
@ConfigurationProperties(prefix = "caching")
public class RedisCachingConfig {

    /**
     * 分组配置项
     */
    @Getter
    @Setter
    private Map<String, Long> ttlmap;

    @Bean
    public CacheManager cacheManager(RedisTemplate<String, Object> redisTemplate) {
        return RedisCacheManager
                .builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory()))
                //缺省配置
                .cacheDefaults(redisCacheConfiguration(redisTemplate, 3600L))
                //分组配置,不需要分组配置可以去掉,不同的组配置不同的缓存过期时间,可以防止"缓存雪崩"
                .withInitialCacheConfigurations(initialRedisCacheConfiguration(redisTemplate))
                .build();
    }

    /**
     * 缺省缓存配置
     */
    private RedisCacheConfiguration redisCacheConfiguration(RedisTemplate<String, Object> redisTemplate, Long ttl) {

        return RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(ttl)) //设置过期,单位秒
                //.disableCachingNullValues() //不允许存储null值,默认可以存储null,缓存null可以防止"缓存穿透"
                //.disableKeyPrefix()  //设置key前面不带前缀,最好不要去掉前缀,否则执行删除缓存时会清空全部缓存
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getStringSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()));
    }

    /**
     * 针对不同的缓存组配置不同的设置
     */
    private Map<String, RedisCacheConfiguration> initialRedisCacheConfiguration(RedisTemplate<String, Object> redisTemplate) {
        Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();
        for (Map.Entry<String, Long> entry : ttlmap.entrySet()) {
            redisCacheConfigurationMap.put(entry.getKey(), redisCacheConfiguration(redisTemplate, entry.getValue()));
        }
        return redisCacheConfigurationMap;
    }

}
  • ttlmap 配置项
yaml 复制代码
caching:
  ttlmap:
    commonCache: 3600
    loginCache: 7200
  • 启动类上要加 @EnableCaching
java 复制代码
@EnableCaching
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
  • 缓存注解使用示例
java 复制代码
@Service
// 缓存分组
@CacheConfig(cacheNames = "commonCache")
public class SystemUserServiceImpl implements ISystemUserService {
   @Autowired
   SystemUserJpaRepository systemUserJpaRepository;

   //向组内添加缓存
   @Cacheable(key = "'SystemUserServiceImpl.findAll'")
   public List<SystemUser> findAll() {
      List<SystemUser> systemUserList = systemUserJpaRepository.findAll();
      return systemUserList;
   }
   //向组内添加缓存
   @Cacheable(key = "'SystemUserServiceImpl.findById_'+ #userId")
   public SystemUser findById(String userId) {
      return systemUserJpaRepository.findById(userId);
   }
   // 删除组内指定缓存
   @CacheEvict(key = "'SystemUserServiceImpl.findById_'+ #userId")
   public void deleteById(String userId) {
      return systemUserJpaRepository.deleteById(userId);
   }
   // 删除本组全部缓存
   @CacheEvict(allEntries = true, beforeInvocation = true)
   public SystemUser add(SystemUser user) {
      systemUserJpaRepository.save(user);
      return user;
   }
}
相关推荐
填满你的记忆2 小时前
【从零开始——Redis 进化日志|Day5】分布式锁演进史:从 SETNX 到 Redisson 的完美蜕变
java·数据库·redis·分布式·缓存
難釋懷2 小时前
Jedis快速入门
redis·缓存
小北方城市网2 小时前
SpringBoot 集成 MinIO 实战(对象存储):实现高效文件管理
java·spring boot·redis·分布式·后端·python·缓存
程序员泠零澪回家种桔子3 小时前
RAG自查询:让AI精准检索的秘密武器
人工智能·后端·算法
曹轲恒3 小时前
SpringBoot配置文件(1)
java·spring boot·后端
码农水水3 小时前
得物Java面试被问:大规模数据的分布式排序和聚合
java·开发语言·spring boot·分布式·面试·php·wpf
Chan163 小时前
【 微服务SpringCloud | 模块拆分 】
java·数据结构·spring boot·微服务·云原生·架构·intellij-idea
guslegend3 小时前
SpringBoot 全局异常处理
spring boot
SenChien3 小时前
Java大模型应用开发day06-天机ai-学习笔记
java·spring boot·笔记·学习·大模型应用开发·springai