spring boot利用redis作为缓存

news2024/11/18 21:31:35

一、缓存介绍

         在 Spring Boot 中,可以使用 Spring Cache abstraction 来实现缓存功能。Spring Cache abstraction 是 Spring 框架提供的一个抽象层,它对底层缓存实现(如 Redis、Ehcache、Caffeine 等)进行了封装,使得在不同的缓存实现之间切换变得更加方便。

        Spring Cache Abstraction 的实现原理主要是通过在运行时动态创建代理对象来实现的。当一个带有缓存注解的方法被调用时,代理对象首先检查指定的缓存中是否已有方法的返回值,如果缓存中有,则直接返回缓存中的值,否则调用原方法获取返回值,并将返回值存入缓存中,再返回给调用者。

        在具体实现上,Spring Cache Abstraction 依赖于 CacheManager 和 Cache 两个接口来实现对缓存的管理和操作。CacheManager 接口提供了获取特定缓存的实例的能力,而 Cache 接口则提供了实际的缓存操作,如 get、put 和 evict 等。

        同时,在 Spring Boot 中,我们可以通过配置来指定使用的缓存类型以及其他相关属性,比如缓存的过期时间、最大缓存数量等。

二、利用redis实现缓存

spring boot的整体的设计思路是约定大于配置,约定俗成,第一步,我们需要引入redis和cache的相关的依赖

 <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>
<dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

注意:commons-pool2必须引入,不然可能会报java.lang.NoClassDefFoundError: org/apache/commons/pool2/impl/GenericObjectPoolConfig错误

第二步,配置spring boot配置文件application.yml

spring:
  redis:
    host: 127.0.0.1
    password:
    database: 0
    port: 6379
    lettuce:
      pool:
        max-idle: 8
        max-active: 8
        max-wait: 3000ms
        min-idle: 0
  cache:
    # 指定Redis作为缓存实现
    type: redis
    # 指定项目中的cacheNames
    cache-names:
      - USERS
    redis:
      # 缓存过期时间为10分钟,单位为毫秒
      time-to-live: 600000
      # 是否允许缓存空数据,当查询到的结果为空时缓存空数据到redis中
      cache-null-values: true
      # 为Redis的KEY拼接前缀
      key-prefix: "BOOT_CACHE:"
      # 是否拼接KEY前缀
      use-key-prefix: true
      # 是否开启缓存统计
      enable-statistics: false

第三步,配置序列化器

@Configuration
public class RedisConfig extends CachingConfigurerSupport {
    @Bean
    public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {
        // 获取Properties中Redis的配置信息
        CacheProperties.Redis redisProperties = cacheProperties.getRedis();
        // 获取RedisCacheConfiguration的默认配置对象
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        // 指定序列化器为GenericJackson2JsonRedisSerializer
        config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        // 过期时间设置
        if (redisProperties.getTimeToLive() != null) {
            config = config.entryTtl(redisProperties.getTimeToLive());
        }
        // KEY前缀配置
        if (redisProperties.getKeyPrefix() != null) {
            config = config.prefixCacheNameWith(redisProperties.getKeyPrefix());
        }
        // 缓存空值配置
        if (!redisProperties.isCacheNullValues()) {
            config = config.disableCachingNullValues();
        }
        // 是否启用前缀
        if (!redisProperties.isUseKeyPrefix()) {
            config = config.disableKeyPrefix();
        }
        return config;
    }
}

第四步,开启缓存-@EnableCaching

@SpringBootApplication
@EnableCaching
public class Application {

    public static void main(String[] args) throws Exception {
        SpringApplication springApplication=new SpringApplication(Application.class);
        springApplication.setBannerMode(Banner.Mode.OFF);
        springApplication.run(args);
    }
}

到此,我们利用redis作为spring boot的缓存已经搭建好了,下面我们来做个测试,这里就不使用数据库了,我们使用数据来自己模拟数据库数据查询,模拟数据访问层

@Repository
@Slf4j
public class UserMapper {

    public final Map<String, SystemUser> map = new HashMap<>();

    @PostConstruct
    public void init(){
        SystemPermissions permissions1 = new SystemPermissions("1", "query");
        SystemPermissions permissions2 = new SystemPermissions("2", "add");
        Set<SystemPermissions> permissionsSet = new HashSet<>();
        permissionsSet.add(permissions1);
        permissionsSet.add(permissions2);
        SystemRole role = new SystemRole("1", "admin", permissionsSet);
        Set<SystemRole> roleSet = new HashSet<>();
        roleSet.add(role);
        SystemUser user = new SystemUser();
        user.setUserName("test");
        user.setUserId(UUID.randomUUID().toString());
        user.setUserPwd("123456");
        user.setSystemRoles(roleSet);

        map.put(user.getUserName(), user);

        Set<SystemPermissions> permissionsSet1 = new HashSet<>();
        permissionsSet1.add(permissions1);
        SystemRole role1 = new SystemRole("2", "user", permissionsSet1);
        Set<SystemRole> roleSet1 = new HashSet<>();
        roleSet1.add(role1);
        SystemUser user1 = new SystemUser();
        user1.setUserName("test1");
        user1.setUserId(UUID.randomUUID().toString());
        user1.setUserPwd("123456");
        user1.setSystemRoles(roleSet1);

        map.put(user1.getUserName(), user1);
    }

    public SystemUser queryUser(String userName){
        log.error("queryUser_没有走缓存:"+userName);
        return map.get(userName);
    }
}

以上类是自己的类,自己实现时可以换成自己的,编写service

public interface UserService {

    SystemUser getUserByName(String userName);

}


@Service
public class UserServiceImpl implements UserService{

    private final UserMapper userMapper;

    public UserServiceImpl(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Cacheable(cacheNames = "USERS",key = "#userName")
    @Override
    public SystemUser getUserByName(String userName) {
        return userMapper.queryUser(userName);
    }
}

编写controller

@RestController
@Slf4j
public class UserController {

  private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("queryUser")
    public JsonResult getUser(String userName){
        SystemUser user=userService.getUserByName(userName);
        return new JsonResult<>("0", "查询成功", user);
    }
}

测试,可以看到,此时我们的redis中没有数据

第一次,请求没有走缓存,我们再看redis,已经有了数据,第二次请求直接拿了redis缓存中的数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1138443.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue实现多时间文字条件查询

// 搜索功能 // 获取搜索框内容 const dateOneref() const dateTworef() // 重新创建数组 const itemList ref([]); const query()>{console.log(formattedDateTime.value);console.log(list.value);itemList.value list.value.filter(item > {//获取数据框的内容是否与…

垃圾回收系统小程序

在当今社会&#xff0c;废品回收不仅有利于环境保护&#xff0c;也有利于资源的再利用。随着互联网技术的发展&#xff0c;个人废品回收也可以通过小程序来实现。本文将介绍如何使用乔拓云网制作个人废品回收小程序。 1. 找一个合适的第三方制作平台/工具&#xff0c;比如乔拓云…

C++之Linux syscall实例总结(二百四十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

进程和多线程

目录 进程 1. 如何管理进程 2. 进程调度 3. 内存管理 4. 进程间通信 多线程 线程和进程的关系&#xff1a; 线程安全问题 进程 一个正在运行的程序,就是一个 进程,进程是一个重要的 "软件资源",是由操作系统内核负责管理的。每个进程都对应一些资源,在上图中…

【面试经典150 | 栈】简化路径

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;字符串数组模拟栈 其他语言python3 写在最后 Tag 【栈】【字符串】 题目来源 71. 简化路径 题目解读 将 Unix 风格的绝对路径转化成更加简洁的规范路径。字符串中会出现 字母、数字、/、_、. 和 .. 这几种字符&#…

c语言之源码反码和补码

c语言源码反码和补码 c语言之源码反码和补码 c语言源码反码和补码一、源码反码补码的介绍二、源码反码补码例子三、源码反码补码练习 一、源码反码补码的介绍 原码、反码、补码是计算机中对数字的二进制表示方法。 原码&#xff1a;将最高位作为符号位&#xff08;0表示正&…

sipp3.6多方案压测脚本

概述 SIP压测工具sipp&#xff0c;免费&#xff0c;开源&#xff0c;功能足够强大&#xff0c;配置灵活&#xff0c;优点多。 有时候我们需要模拟现网的生产环境来压测&#xff0c;就需要同时有多个sipp脚本运行&#xff0c;并且需要不断的调整呼叫并发。 通过python脚本的子…

一文讲透 “中间层” 思想

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《EffectiveJava》独家解析》专栏作者。 热门文章推荐&…

【打靶】vulhub打靶复现系列3---Chronos

【打靶】vulhub打靶复现系列3---Chronos 一、主机探测 结合之前的方法&#xff08;arp探测、ping检测&#xff09;&#xff0c;因为我们的靶机和攻击机都在第二层&#xff0c;所以打靶时候我们更依赖arp协议 tips&#xff1a;我在运行期间发现&#xff0c;netdiscover窗口没关…

vue中如何给后端过来的数组中每一个对象加一个新的属性和新的对象(不影响后端的原始数据)

方法&#xff1a; 先看后端的原数据 1、给数组中每一个对象加一个新的属性&#xff1a; 输出查看数组list的值&#xff1a; 2、给数组list加入新的对象&#xff1a; 输出结果&#xff1a; 3、总结&#xff1a; 如果是数组中每个对象新增属性就用map遍历每个对象加入新增的属性…

Baichuan2:Open large-scale language models

1.introduction baichuan2基于2.6万亿个token进行训练。 2.pre-training 2.1 pre-training data 数据处理&#xff1a;关注数据频率和质量。数据频率依赖于聚类和去重&#xff0c;构建了一个支持LSH型特征和稠密embedding特征的大规模去重和聚类系统&#xff0c;单个文档、段…

Java基于ssm+vue开发的失物招领小程序

演示视频&#xff1a; 小程序 https://www.bilibili.com/video/BV1sg4y1d75T/?share_sourcecopy_web&vd_source11344bb73ef9b33550b8202d07ae139b 管理员 https://www.bilibili.com/video/BV1UH4y167xe/?share_sourcecopy_web&vd_source11344bb73ef9b33550b8202d07a…

论文阅读 - Hidden messages: mapping nations’ media campaigns

论文链接&#xff1a; https://link.springer.com/content/pdf/10.1007/s10588-023-09382-7.pdf 目录 1 Introduction 2 The influence model 2.1 The influence‑model library 3 Data 4 Methodology 4.1 Constructing observations 4.2 Learning the state‑transiti…

编写虚拟UART驱动程序-框架

一、框架回顾 二、编写UART驱动要做的事 1.注册一个uart_driver 2. 对于每一个port&#xff0c;都会在设备树里面有一个节点 3. 设备树里的节点和platform_driver节点匹配 4. 当platform_dirver的probe函数被调用时&#xff0c;可以获得设备树里的信息&#xff0c;从而把每个串…

AutoConfigurationPackages.Registrar.class源码阅读

类作用 &#xff5b;link ImportBeanDefinitionRegistrar&#xff5d;存储来自导入的基本包配置。 registerBeanDefinitions 作用&#xff1a; 根据导入的有Configuration注解的类给定的注释元数据注册bean定义。由于与&#xff5b;codeConfiguration&#xff5d;相关的生命周…

HarmonyOS开发:NodeJs脚本实现组件化动态切换

前言 上篇文章&#xff0c;我们使用NodeJs脚本完成了HarmonyOS项目的组件化运行&#xff0c;但是由于脚本是基于4.0.0.400版本的DevEco Studio开发的&#xff0c;可能在配置文件的修改上有些许差距&#xff0c;那么遇到这种情况怎么办&#xff0c;一种是再写一套针对性的脚本文…

谁能想到,字节2023校招起薪40w+

大家好&#xff0c;我是老原。 转眼2023也来到了年底&#xff0c;每年的校招季&#xff0c;都是大厂上演抢人大战的时机&#xff0c;公布薪资和“开奖”一样刺激。 就拿互联网新贵—字节跳动来说&#xff0c;按照字节15薪计算白菜第一年的总包都超过40W了&#xff0c;对比去年…

【Linux】VM及WindowsServer安装

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《微信小程序开发实战》。&#x1f3af;&#x1f3a…

电脑怎么共享屏幕?电脑屏幕共享软件分享!

如何控制某人的电脑屏幕&#xff1f; 有时我们可能需要远程控制某人的计算机屏幕&#xff0c;例如&#xff0c;为我们的客户提供远程支持&#xff0c;远程帮助朋友或家人解决计算机问题&#xff0c;或在家中与同事完成团队合作。那么&#xff0c;电脑怎么共享屏幕&#xff…

皮卡丘RCE靶场通关攻略

皮卡丘RCE靶场通关攻略 文章目录 皮卡丘RCE靶场通关攻略RCE(remote command/code execute)概述远程系统命令执行启动环境漏洞练习第一关exec "ping"第二关 exec "eval" RCE(remote command/code execute)概述 RCE漏洞&#xff0c;可以让攻击者直接向后台服…