Springboot+Redis实现分布式缓存详细教程(附源码下载)

Springboot-cli 开发脚手架系列

Springboot系列:Springboot+Redis优雅的实现分布式缓存(redisTemplate及Annotation)


文章目录

  • Springboot-cli 开发脚手架系列
  • 前言
    • 1. 环境
    • 2. 配置redisTemplate
    • 3. 编写实体,并实现序列化接口
    • 4. 测试手动存储
    • 5. 注解方式实现
    • 6. 源码分享


前言

致力于让开发者快速搭建基础环境并让应用跑起来,并提供使用示例供使用者参考,快速上手。
本博客项目源码地址:

  • 项目源码github地址
  • 项目源码国内gitee地址

1. 环境

  • 引入依赖pom.xml
     
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-redisartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.sessiongroupId>
            <artifactId>spring-session-data-redisartifactId>
        dependency>
        
        <dependency>
            <groupId>org.apache.commonsgroupId>
            <artifactId>commons-pool2artifactId>
            <version>2.10.0version>
        dependency>
  • application.yml
spring:
  # redis 配置
  redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    #连接超时时间
    timeout: 3000
    password: 123456
    #连接池配置
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: -1

2. 配置redisTemplate

  • 编写RedisConfig.java配置,配置序列化方式
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    /**
     * RedisTemplate 默认使用 jdk 序列化,存在乱码等问题,将 value 的序列化方式换为 Jackson 后,value 中不再出现乱码。
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(RedisSerializer.string());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setEnableTransactionSupport(true);
        return template;
    }
}
  • 封装RedisUtils.java
/**
 * Redis工具类
 */
@Component
@Slf4j
public class RedisUtils {

    @Resource
    private RedisTemplate<String, Object> rt;

    private static RedisTemplate<String, Object> redisTemplate;

    @PostConstruct
    public void init() {
        // bean赋值给静态变量
        redisTemplate = rt;
    }

    /**
     * 存储
     *
     * @param cacheKey     缓存key
     * @param value   值
     * @param timeout 超时时间 秒
     */
    public static void save(String cacheKey, Object value, long timeout) {
        redisTemplate.opsForValue().set(cacheKey, value, timeout, TimeUnit.SECONDS);
    }

    public static void save(String cacheKey, Object value) {
        save(cacheKey, value, -1);
    }

    /**
     * 获取
     *
     * @param cacheKey 缓存key
     * @param c   返回值类型
     * @return c类型的对象
     */
    public static <T> T get(String cacheKey, Class<T> c) {
        Object o = redisTemplate.opsForValue().get(cacheKey);
        return JSON.parseObject(JSON.toJSONString(o), c);
    }

    /**
     * 缓存是否存在
     *
     * @param cacheKey 缓存key
     * @return true 存在
     */
    public static boolean hasKey(String cacheKey) {
        return Boolean.TRUE.equals(redisTemplate.hasKey(cacheKey));
    }

    /**
     * 添加到set集合
     *
     * @param cacheKey 缓存key
     * @param value  值 一个或多个
     */
    public static void addForSet(String cacheKey, Object... value) {
        redisTemplate.opsForSet().add(cacheKey, value);
    }

    /**
     * 获取set集合
     *
     * @param cacheKey 缓存
     * @param c      返回值类型
     * @return c类型的set集合
     */
    public static <T> Set<T> getForSet(String cacheKey, Class<T> c) {
        Set<Object> set = redisTemplate.boundSetOps(cacheKey).members();
        if (Objects.isNull(set)) {
            return null;
        }
        return set.stream().map(o -> JSON.parseObject(JSON.toJSONString(o), c)).collect(Collectors.toSet());
    }

    /**
     * 设置过期时间
     *
     * @param cacheKey    缓存 key
     * @param timeout 过期时间(秒)
     */
    public static void expire(String cacheKey, long timeout) {
        redisTemplate.expire(cacheKey, timeout, TimeUnit.MINUTES);
    }

    /**
     * 删除指定缓存
     *
     * @param cacheKey 缓存key
     */
    public static Boolean delete(String cacheKey) {
        return redisTemplate.delete(cacheKey);
    }

    /**
     * 指定元素删除
     *
     * @param cacheKey  缓存
     * @param objKey 集合元素
     */
    public static void remove(String cacheKey,String objKey) {
        redisTemplate.boundSetOps(cacheKey).remove(objKey);
    }

}

3. 编写实体,并实现序列化接口

  • User.java
@Data
@Accessors(chain = true)
public class User implements Serializable {

    private static final long serialVersionUID = 1L;
    /**
     * 用户id
     */
    private Long userId;

    /**
     * 用户名
     */
    private String username;

    /**
     * 性别
     */
    private String sex;

    /**
     * 备注
     */
    private String remark;
}
  • 注意:实体一定要加上序列化
    Springboot+Redis实现分布式缓存详细教程(附源码下载)_第1张图片

4. 测试手动存储

  • 编写测试接口
@RestController
@RequiredArgsConstructor
public class IndexController {
    /**
     * 手动设置缓存
     */
    @GetMapping("/set")
    public String set() {
        RedisUtils.save("key", new User().setUserId(999L).setSex("男").setUsername("王小锤"), 6000);
        return "设置成功 !";
    }

    /**
     * 手动获取缓存
     */
    @GetMapping("/get")
    public User get() {
        return RedisUtils.get("key", User.class);
    }
}
  • 启动项目浏览器输入ip+端口+/set 添加缓存
    Springboot+Redis实现分布式缓存详细教程(附源码下载)_第2张图片

  • ip+端口+/get 获取缓存
    Springboot+Redis实现分布式缓存详细教程(附源码下载)_第3张图片

5. 注解方式实现

  • 在前面配置RedisConfig.java中加入如下配置
   /**
     * 此处重写·springboot注解方式·缓存的Key生成规则
     * key=包+方法名+参数
     */
    @Override
    @Bean
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append(method.getName());
            for (Object obj : params) {
                sb.append(Objects.nonNull(obj) ? obj.toString() : "null");
            }
            System.out.println(sb);
            return sb.toString();
        };
    }

    /**
     * 此处重写·springboot注解方式·缓存的序列化方式及有效时间
     * key=包+方法名+参数
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                // 将::改写为一个:
                .computePrefixWith(cacheName -> cacheName + ":")
                // 设置缓存有效期24小时
                .entryTtl(Duration.ofHours(24))
                // 禁止空值
                .disableCachingNullValues()
                // 设置序列化规则
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(cacheConfiguration)
                .build();
    }
  • 编写service 接口层
  • IUserService.java
public interface IUserService {
    /**
     * 缓存测试
     *
     * @param id 用户id 随便输入
     * @return 用户数据
     */
    User getUser(Long id);

    /**
     * 删除缓存测试
     *
     * @param id 用户id 随便输入
     */
    void delUser(Long id);
}
  • 编写实现类UserServiceImpl.java,模拟数据库存储
  • 在我们需要用缓存的方法上添加@Cacheable(value = "user-key")
  • 需要刷新缓存的地方添加@CacheEvict(value = "user-key", allEntries = true)
@Service
@Slf4j
public class UserServiceImpl implements IUserService {

    @Override
    @Cacheable(value = "user-key")
    public User getUser(Long id) {
        return this.getUserInfo(id);
    }

    @Override
    @CacheEvict(value = "user-key", allEntries = true)
    public void delUser(Long id) {
        this.delUserInfo(id);
    }

    public void delUserInfo(Long id) {
        log.info("删除{}用户数据执行了!!", id);
    }

    /**
     * 模拟数据库查询
     */
    private User getUserInfo(Long id) {
        log.info("获取用户数据执行了!!");
        return new User().setUserId(id).setUsername("王小锤").setSex("男").setRemark("注解方式aop实现缓存");
    }
}
  • 效果
    观察控制台我们可以发现,当我们查询的id一样时,只有第一次会触发getUserInfo方法,之后就会走缓存进行获取,只有当id不一样时,才会从新去调用getUserInfo方法。
    Springboot+Redis实现分布式缓存详细教程(附源码下载)_第4张图片

6. 源码分享

本项目已收录

  • Springboot-cli开发脚手架,集合各种常用框架使用案例,完善的文档,致力于让开发者快速搭建基础环境并让应用跑起来,并提供丰富的使用示例供使用者参考,快速上手。
  • 项目源码github地址
  • 项目源码国内gitee地址

你可能感兴趣的:(SpringBoot-cli,开发脚手架,redis,spring,boot,缓存)