SpringBoot 缓存

个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~

个人主页:.29.的博客

学习社区:进去逛一逛~

目录


一、缓存的作用


缓存

  • 缓存时一种介于数据永久存储介质与数据应用之间的数据临时存储介质
  • 使用缓存可以有效的减少低速数据读取过程的次数(例如磁盘IO),提高系统性能
  • 缓存不仅可以用于提高永久性存储介质的数据读取效率,还可以提供临时的数据存储空间

二、SpringBoot启用缓存


SpringBoot提供了缓存技术,方便缓存的使用

  • 启用缓存
  • 设置进入缓存的数据
  • 设置读取缓存的数据

pom.xml导入缓存相关的起步依赖

xml 复制代码
        <!--缓存功能的起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

SpringBoot启动类,添加@EnableCaching注解,启用缓存

java 复制代码
@SpringBootApplication
@EnableCaching        //此注解表示开启缓存功能
public class Springboot4CacheApplication {

    public static void main(String[] args) {
        SpringApplication.run(Springboot4CacheApplication.class, args);
    }

}

业务层组件,使用@Cacheable注解

value属性:存放缓存的位置,可随意定义

key属性:使用 # + 参数名 的方式设置缓存的数据

java 复制代码
@Override
@Cacheable(value = "cacheSpace",key = "#id")
public Book getById(Integer id){
    return bookMapper.selectById(id);
}

三、SpringBoot可整合的缓存技术


  • SpringBoot提供的缓存技术除了提供默认的方案,还可以对其他缓存技术进行整合,统一接口,方便缓存技术的开发与管理。

常见的SpringBoot可整合的缓存技术

  • Generic
  • JCache
  • Ehcache
  • Hazelcast
  • Infinispan
  • Couchbase
  • Redis
  • Caffenine
  • Simple(默认)
  • memcached

四、缓存使用案例------收集验证码


需求

  • 输入手机号获取验证码,组织文档以短信形式发送给用户(页面模拟)
  • 输入手机号和验证码以验证结果

需求分析

  • 提供Controller组件,传入手机号,业务层通过手机号计算出独有的6位数验证码数据,存入缓存后返回此数据;
  • 提供Controller组件,传入手机号与验证码,业务层通过手机号从缓存中读取验证码,与输入的验证码进行比对,返回最终结果;

实体类开发

lombok快速开发实体类

xml 复制代码
        <!--导入lombok依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

--

java 复制代码
import lombok.Data;

/**
 * @author .29.
 * @create 2023-04-02 22:08
 * 使用@Data注解,提供Getter、Setter和toString()
 */
@Data
public class SMSCode {
    //电话号码
    private String phoneNumber;
    //验证码
    private String code;
}

业务层开发

业务层接口

java 复制代码
/**
 * @author .29.
 * @create 2023-04-02 22:12
 */

public interface SMSCodeService {
    //模拟向sm卡发送验证码
    public String sendCodeToSMS(String phoneNumber);

    //验证验证码是否正确
    public boolean checkCode(SMSCode smsCode);
}

业务层接口实现类

  • 业务层组件中,使用了缓存功能,缓存功能的开启需要在SpringBoot工程的启动类中使用@EnableCaching开启缓存功能。
java 复制代码
/**
 * @author .29.
 * @create 2023-04-02 22:15
 */
@Service
public class SMSCodeServiceImpl implements SMSCodeService {
    @Autowired
    private CodeUtils utils;  //自动装配工具类对象(工具类中提供了生成验证码的算法)

    @Override
    //@Cacheable注解不适用,缓存会被读取,导致前后两次验证码重复
    //@Cacheable(value="smsCode",key = "#phoneNumber")
    //@CachePut注解,缓存只可放不可读
    @CachePut(value="smsCode",key = "#phoneNumber")
    public String sendCodeToSMS(String phoneNumber) {
        return utils.generator(phoneNumber);
    }

    @Override
    public boolean checkCode(SMSCode smsCode) {
        //取出内存中的验证码与传递过来的参数比对,如果相同,返回true
        String code = smsCode.getCode();
        String cacheCode = utils.get(smsCode.getPhoneNumber());
        return cacheCode.equals(code);
    }
}

工具类(生成验证码)

工具类实现

java 复制代码
/**
 * @author .29.
 * @create 2023-04-02 22:26
 */
@Component
public class CodeUtils {
    //为不足六位数的验证码补0用
    private String[] patch = {"000000","00000","0000","000","00","0",""};

    //加密,生成验证码
    public String generator(String phoneNumber){
        //获取手机号的hashCode值
        int hash = phoneNumber.hashCode();
        //设置一个加密码
        int encryption = 20230209;
        //获取第一次加密结果
        long result = hash ^ encryption;
        //第二次加密,第一次加密结果与当前时间进行异或操作
        long nowTime = System.currentTimeMillis();
        result = result ^ nowTime;
        //获取第二次加密结果的后六位
        long code = result % 1000000;
        code = code < 0 ? -code : code;//避免验证码为负值
        //转化为字符串
        String codeStr = code+"";
        int len = codeStr.length();
        return patch[len]+codeStr;
    }

    //设置phoneNumber的缓存,方法返回值为null,有缓存则返回缓存数据,没有才返回null
    @Cacheable(value="smsCode",key = "#phoneNumber")
    public String get(String phoneNumber){
        return null;
    }

}

控制层开发

java 复制代码
/**
 * @author .29.
 * @create 2023-04-02 22:16
 */
//用于标记控制器类。@RestController 是 @Controller 和 @ResponseBody 的组合注解,用于标记 RESTful 风格的控制器类。
@RestController
@RequestMapping("/sms")
public class SMSCodeController {

    @Autowired
    private SMSCodeService service; //自动装配业务层组件

    //获取验证码
    @GetMapping
    public String getCode(String phoneNumber){
        String code = service.sendCodeToSMS(phoneNumber);
        return code;
    }

    //判断验证码是否正确
    @PostMapping
    public boolean checkCode(SMSCode smsCode){
        boolean result = service.checkCode(smsCode);
        return result;
    }
}

SpringBoot启动类

  • 注意要开启缓存功能
java 复制代码
@SpringBootApplication
@EnableCaching        //此注解表示开启缓存功能
public class Springboot4CacheApplication {

    public static void main(String[] args) {
        SpringApplication.run(Springboot4CacheApplication.class, args);
    }

}

测试

运行案例工程

使用国产postMAN测试功能

  • 使用页面模拟接收验证码:(每次发送请求,验证码都不会重复)
  • 模拟验证码比对校验:(只有当次手机号码与验证码匹配,才会返回true)

五、变更缓存供应商Ehcache


pom.xml导入Ehcache依赖

xml 复制代码
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
        </dependency>

application.yml配置文件

  • 设置使用ehcache的缓存
yaml 复制代码
spring:
  cacahe:
    type: ehcache

配置Ehcache的xml配置文件

  • 其中的name属性值,需要保证与你注解中设置的缓存位置一致
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <diskStore path="D:\ehcache" />

    <!--默认缓存策略 -->
    <!-- external:是否永久存在,设置为true则不会被清除,此时与timeout冲突,通常设置为false-->
    <!-- diskPersistent:是否启用磁盘持久化-->
    <!-- maxElementsInMemory:最大缓存数量-->
    <!-- overflowToDisk:超过最大缓存数量是否持久化到磁盘-->
    <!-- timeToIdleSeconds:最大不活动间隔,设置过长缓存容易溢出,设置过短无效果,可用于记录时效性数据,例如验证码-->
    <!-- timeToLiveSeconds:最大存活时间-->
    <!-- memoryStoreEvictionPolicy:缓存清除策略-->
    <defaultCache
        eternal="false"
        diskPersistent="false"
        maxElementsInMemory="1000"
        overflowToDisk="false"
        timeToIdleSeconds="60"
        timeToLiveSeconds="60"
        memoryStoreEvictionPolicy="LRU" />

    <cache
        name="smsCode"  
        eternal="false"
        diskPersistent="false"
        maxElementsInMemory="1000"
        overflowToDisk="false"
        timeToIdleSeconds="10"
        timeToLiveSeconds="10"
        memoryStoreEvictionPolicy="LRU" />

</ehcache>
  • 完成上述配置,缓存技术也就更换完成了。
相关推荐
方圆想当图灵4 分钟前
缓存之美:万文详解 Caffeine 实现原理(下)
java·redis·缓存
老大白菜5 分钟前
GoFrame 缓存组件
缓存·goframe
栗豆包18 分钟前
w175基于springboot的图书管理系统的设计与实现
java·spring boot·后端·spring·tomcat
等一场春雨1 小时前
Java设计模式 十四 行为型模式 (Behavioral Patterns)
java·开发语言·设计模式
萧若岚1 小时前
Elixir语言的Web开发
开发语言·后端·golang
Channing Lewis1 小时前
flask实现重启后需要重新输入用户名而避免浏览器使用之前已经记录的用户名
后端·python·flask
Channing Lewis1 小时前
如何在 Flask 中实现用户认证?
后端·python·flask
酱学编程2 小时前
java中的单元测试的使用以及原理
java·单元测试·log4j
我的运维人生2 小时前
Java并发编程深度解析:从理论到实践
java·开发语言·python·运维开发·技术共享
一只爱吃“兔子”的“胡萝卜”2 小时前
2.Spring-AOP
java·后端·spring