SpringBoot实用开发篇第四章(整合缓存技术)

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: SpringBoot实用开发篇第四章(整合缓存技术)

通过本章的学习,可以将之前学习的springboot整合第三方技术的思想贯彻到底,还是那三板斧。导坐标、做配置、调API。

springboot能够整合的技术实在是太多了,可以说是万物皆可整。本章将从企业级开发中常用的一些技术作为出发点,对各种各样的技术进行整合。

一、缓存

企业级应用主要作用是信息处理,当需要读取数据时,由于受限于数据库的访问效率,导致整体系统性能偏低。

应用程序直接与数据库打交道,访问效率低

为了改善上述现象,开发者通常会在应用程序与数据库之间建立一种临时的数据存储机制,该区域中的数据在内存中保存,读写速度较快,可以有效解决数据库访问效率低下的问题。这一块临时存储数据的区域就是缓存。

使用缓存后,应用程序与缓存打交道,缓存与数据库打交道,数据访问效率提高

缓存是什么?缓存是一种介于数据永久存储介质与应用程序之间的数据临时存储介质,使用缓存可以有效的减少低速数据读取过程的次数(例如磁盘IO),提高系统性能。此外缓存不仅可以用于提高永久性存储介质的数据读取效率,还可以提供临时的数据存储空间。而springboot提供了对市面上几乎所有的缓存技术进行整合的方案,下面就一起开启springboot整合缓存之旅。

二、SpringBoot内置缓存解决方案

springboot技术提供有内置的缓存解决方案,可以帮助开发者快速开启缓存技术,并使用缓存技术进行数据的快速操作,例如读取缓存数据和写入数据到缓存。

步骤①:导入springboot提供的缓存技术对应的starter

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

步骤②:启用缓存,在引导类上方标注注解@EnableCaching配置springboot程序中可以使用缓存

@SpringBootApplication
//开启缓存功能
@EnableCaching
public class Springboot19CacheApplication {
    public static void main(String[] args) {
        SpringApplication.run(Springboot19CacheApplication.class, args);
    }
}

步骤③:设置操作的数据是否使用缓存

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    private BookDao bookDao;
    @Cacheable(value="cacheSpace",key="#id")
    public Book getById(Integer id) {
        return bookDao.selectById(id);
    }
}

在业务方法上面使用注解@Cacheable声明当前方法的返回值放入缓存中,其中要指定缓存的存储位置,以及缓存中保存当前方法返回值对应的名称。上例中value属性描述缓存的存储位置,可以理解为是一个存储空间名,key属性描述了缓存中保存数据的名称,使用#id读取形参中的id值作为缓存名称。

使用@Cacheable注解后,执行当前操作,如果发现对应名称在缓存中没有数据,就正常读取数据,然后放入缓存;如果对应名称在缓存中有数据,就终止当前业务方法执行,直接返回缓存中的数据。

三、手机验证码案例

为了便于下面演示各种各样的缓存技术,我们创建一个手机验证码的案例环境,模拟使用缓存保存手机验证码的过程。

手机验证码案例需求如下:

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

为了描述上述操作,我们制作两个表现层接口,一个用来模拟发送短信的过程,其实就是根据用户提供的手机号生成一个验证码,然后放入缓存,另一个用来模拟验证码校验的过程,其实就是使用传入的手机号和验证码进行匹配,并返回最终匹配结果。下面直接制作本案例的模拟代码,先以上例中springboot提供的内置缓存技术来完成当前案例的制作。

步骤①:导入springboot提供的缓存技术对应的starter

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

步骤②:启用缓存,在引导类上方标注注解@EnableCaching配置springboot程序中可以使用缓存

@SpringBootApplication
//开启缓存功能
@EnableCaching
public class Springboot19CacheApplication {
    public static void main(String[] args) {
        SpringApplication.run(Springboot19CacheApplication.class, args);
    }
}

步骤③:定义验证码对应的实体类,封装手机号与验证码两个属性

@Data
public class SMSCode {
    private String tele;
    private String code;
}

步骤④:定义验证码功能的业务层接口与实现类

public interface SMSCodeService {
    public String sendCodeToSMS(String tele);
    public boolean checkCode(SMSCode smsCode);
}
@Service
public class SMSCodeServiceImpl implements SMSCodeService {
    @Autowired
    private CodeUtils codeUtils;
    @CachePut(value = "smsCode", key = "#tele")
    public String sendCodeToSMS(String tele) {
        String code = codeUtils.generator(tele);
        return code;
    }
    public boolean checkCode(SMSCode smsCode) {
        //取出内存中的验证码与传递过来的验证码比对,如果相同,返回true
        String code = smsCode.getCode();
        String cacheCode = codeUtils.get(smsCode.getTele());
        return code.equals(cacheCode);
    }
}

获取验证码后,当验证码失效时必须重新获取验证码,因此在获取验证码的功能上不能使用@Cacheable注解,@Cacheable注解是缓存中没有值则放入值,缓存中有值则取值。此处的功能仅仅是生成验证码并放入缓存,并不具有从缓存中取值的功能,因此不能使用@Cacheable注解,应该使用仅具有向缓存中保存数据的功能,使用@CachePut注解即可。

对于校验验证码的功能建议放入工具类中进行。

步骤⑤:定义验证码的生成策略与根据手机号读取验证码的功能

@Component
public class CodeUtils {
    private String [] patch = {"000000","00000","0000","000","00","0",""};
    public String generator(String tele){
        int hash = tele.hashCode();
        int encryption = 20206666;
        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;
    }
    @Cacheable(value = "smsCode",key="#tele")
    public String get(String tele){
        return null;
    }
}

步骤⑥:定义验证码功能的web层接口,一个方法用于提供手机号获取验证码,一个方法用于提供手机号和验证码进行校验

@RestController
@RequestMapping("/sms")
public class SMSCodeController {
    @Autowired
    private SMSCodeService smsCodeService;
    
    @GetMapping
    public String getCode(String tele){
        String code = smsCodeService.sendCodeToSMS(tele);
        return code;
    }
    
    @PostMapping
    public boolean checkCode(SMSCode smsCode){
        return smsCodeService.checkCode(smsCode);
    }
}

四、SpringBoot整合Ehcache缓存

手机验证码的案例已经完成了,下面就开始springboot整合各种各样的缓存技术,第一个整合Ehcache技术。Ehcache是一种缓存技术,使用springboot整合Ehcache其实就是变更一下缓存技术的实现方式,话不多说,直接开整

步骤①:导入Ehcache的坐标

<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>

此处为什么不是导入Ehcache的starter,而是导入技术坐标呢?其实springboot整合缓存技术做的是通用格式,不管你整合哪种缓存技术,只是实现变化了,操作方式一样。这也体现出springboot技术的优点,统一同类技术的整合方式。

步骤②:配置缓存技术实现使用Ehcache

spring:
  cache:
    type: ehcache
    ehcache:
      config: ehcache.xml

配置缓存的类型type为ehcache,此处需要说明一下,当前springboot可以整合的缓存技术中包含有ehcach,所以可以这样书写。其实这个type不可以随便写的,不是随便写一个名称就可以整合的。

由于ehcache的配置有独立的配置文件格式,因此还需要指定ehcache的配置文件,以便于读取相应配置

<?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>

注意前面的案例中,设置了数据保存的位置是smsCode

@CachePut(value = "smsCode", key = "#tele")
public String sendCodeToSMS(String tele) {
    String code = codeUtils.generator(tele);
    return code;
} 

这个设定需要保障ehcache中有一个缓存空间名称叫做smsCode的配置,前后要统一。在企业开发过程中,通过设置不同名称的cache来设定不同的缓存策略,应用于不同的缓存数据。

到这里springboot整合Ehcache就做完了,可以发现一点,原始代码没有任何修改,仅仅是加了一组配置就可以变更缓存供应商了,这也是springboot提供了统一的缓存操作接口的优势,变更实现并不影响原始代码的书写。

五、SpringBoot整合Redis缓存

其实springboot支持的缓存技术还很多,下面使用redis技术作为缓存解决方案来实现手机验证码案例。

比对使用Ehcache的过程,加坐标,改缓存实现类型为ehcache,做Ehcache的配置。如果还成redis做缓存呢?一模一样,加坐标,改缓存实现类型为redis,做redis的配置。差别之处只有一点,redis的配置可以在yml文件中直接进行配置,无需制作独立的配置文件。

步骤①:导入redis的坐标

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

步骤②:配置缓存技术实现使用redis

spring:
  redis:
    host: localhost
    port: 6379
  cache:
    type: redis

如果需要对redis作为缓存进行配置,注意不是对原始的redis进行配置,而是配置redis作为缓存使用相关的配置,隶属于spring.cache.redis节点下,注意不要写错位置了。

spring:
  redis:
    host: localhost
    port: 6379
  cache:
    type: redis
    redis:
      use-key-prefix: false
      key-prefix: sms_
      cache-null-values: false
      time-to-live: 10s

总结

springboot使用redis作为缓存实现需要导入redis的坐标

修改设置,配置缓存供应商为redis,并提供对应的缓存配置

六、SpringBoot整合Memcached缓存

目前我们已经掌握了3种缓存解决方案的配置形式,分别是springboot内置缓存,ehcache和redis,本节研究一下国内比较流行的一款缓存memcached。

按照之前的套路,其实变更缓存并不繁琐,但是springboot并没有支持使用memcached作为其缓存解决方案,也就是说在type属性中没有memcached的配置选项,这里就需要更变一下处理方式了。在整合之前先安装memcached。

安装

windows版安装包下载地址:https://www.runoob.com/memcached/window-install-memcached.html

下载的安装包是解压缩就能使用的zip文件,解压缩完毕后会得到如下文件

可执行文件只有一个memcached.exe,使用该文件可以将memcached作为系统服务启动,执行此文件时会出现报错信息,如下:

此处出现问题的原因是注册系统服务时需要使用管理员权限,当前账号权限不足导致安装服务失败,切换管理员账号权限启动命令行

然后再次执行安装服务的命令即可,如下:

memcached.exe -d install

服务安装完毕后可以使用命令启动和停止服务,如下:

memcached.exe -d start    # 启动服务
memcached.exe -d stop   # 停止服务

也可以在任务管理器中进行服务状态的切换

变更缓存为Memcached

由于memcached未被springboot收录为缓存解决方案,因此使用memcached需要通过手工硬编码的方式来使用,于是前面的套路都不适用了,需要自己写了。

memcached目前提供有三种客户端技术,分别是Memcached Client for Java、SpyMemcached和Xmemcached,其中性能指标各方面最好的客户端是Xmemcached,本次整合就使用这个作为客户端实现技术了。下面开始使用Xmemcached

步骤①:导入xmemcached的坐标

<dependency>
    <groupId>com.googlecode.xmemcached</groupId>
    <artifactId>xmemcached</artifactId>
    <version>2.4.7</version>
</dependency>

步骤②:配置memcached,制作memcached的配置类

@Configuration
public class XMemcachedConfig {
    @Bean
    public MemcachedClient getMemcachedClient() throws IOException {
        MemcachedClientBuilder memcachedClientBuilder = new XMemcachedClientBuilder("localhost:11211");
        MemcachedClient memcachedClient = memcachedClientBuilder.build();
        return memcachedClient;
    }
}

memcached默认对外服务端口11211。

步骤③:使用xmemcached客户端操作缓存,注入MemcachedClient对象

@Service
public class SMSCodeServiceImpl implements SMSCodeService {
    @Autowired
    private CodeUtils codeUtils;
    @Autowired
    private MemcachedClient memcachedClient;
    public String sendCodeToSMS(String tele) {
        String code = codeUtils.generator(tele);
        try {
            memcachedClient.set(tele,10,code);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return code;
    }
    public boolean checkCode(SMSCode smsCode) {
        String code = null;
        try {
            code = memcachedClient.get(smsCode.getTele()).toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return smsCode.getCode().equals(code);
    }
}

设置值到缓存中使用set操作,取值使用get操作,其实更符合我们开发者的习惯。

上述代码中对于服务器的配置使用硬编码写死到了代码中,将此数据提取出来,做成独立的配置属性。

定义配置属性

以下过程采用前期学习的属性配置方式进行,当前操作有助于理解原理篇中的很多知识。

定义配置类,加载必要的配置属性,读取配置文件中memcached节点信息

@Component
@ConfigurationProperties(prefix = "memcached")
@Data
public class XMemcachedProperties {
    private String servers;
    private int poolSize;
    private long opTimeout;
}

定义memcached节点信息

memcached:
  servers: localhost:11211
  poolSize: 10
  opTimeout: 3000

在memcached配置类中加载信息

@Configuration
public class XMemcachedConfig {
    @Autowired
    private XMemcachedProperties props;
    @Bean
    public MemcachedClient getMemcachedClient() throws IOException {
        MemcachedClientBuilder memcachedClientBuilder = new XMemcachedClientBuilder(props.getServers());
        memcachedClientBuilder.setConnectionPoolSize(props.getPoolSize());
        memcachedClientBuilder.setOpTimeout(props.getOpTimeout());
        MemcachedClient memcachedClient = memcachedClientBuilder.build();
        return memcachedClient;
    }
}


相关文章
|
5月前
|
机器学习/深度学习 存储 缓存
加速LLM大模型推理,KV缓存技术详解与PyTorch实现
大型语言模型(LLM)的推理效率是AI领域的重要挑战。本文聚焦KV缓存技术,通过存储复用注意力机制中的Key和Value张量,减少冗余计算,显著提升推理效率。文章从理论到实践,详细解析KV缓存原理、实现与性能优势,并提供PyTorch代码示例。实验表明,该技术在长序列生成中可将推理时间降低近60%,为大模型优化提供了有效方案。
936 15
加速LLM大模型推理,KV缓存技术详解与PyTorch实现
|
5月前
|
前端开发 Java 关系型数据库
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
420 7
|
5月前
|
人工智能 Java 数据库
飞算 JavaAI:革新电商订单系统 Spring Boot 微服务开发
在电商订单系统开发中,传统方式耗时约30天,需应对复杂代码、调试与测试。飞算JavaAI作为一款AI代码生成工具,专注于简化Spring Boot微服务开发。它能根据业务需求自动生成RESTful API、数据库交互及事务管理代码,将开发时间缩短至1小时,效率提升80%。通过减少样板代码编写,提供规范且准确的代码,飞算JavaAI显著降低了开发成本,为软件开发带来革新动力。
|
2月前
|
Java 数据库连接 API
Java 8 + 特性及 Spring Boot 与 Hibernate 等最新技术的实操内容详解
本内容涵盖Java 8+核心语法、Spring Boot与Hibernate实操,按考试考点分类整理,含技术详解与代码示例,助力掌握最新Java技术与应用。
105 2
|
5月前
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
385 70
|
3月前
|
缓存 负载均衡 网络协议
电商API接口性能优化技术揭秘:缓存策略与负载均衡详解
电商API接口性能优化是提升系统稳定性和用户体验的关键。本文聚焦缓存策略与负载均衡两大核心,详解其在电商业务中的实践。缓存策略涵盖本地、分布式及CDN缓存,通过全量或部分缓存设计和一致性维护,减少后端压力;负载均衡则利用反向代理、DNS轮询等技术,结合动态调整与冗余部署,提高吞吐量与可用性。文中引用大型及跨境电商平台案例,展示优化效果,强调持续监控与迭代的重要性,为电商企业提供了切实可行的性能优化路径。
|
6月前
|
缓存 NoSQL Java
基于SpringBoot的Redis开发实战教程
Redis在Spring Boot中的应用非常广泛,其高性能和灵活性使其成为构建高效分布式系统的理想选择。通过深入理解本文的内容,您可以更好地利用Redis的特性,为应用程序提供高效的缓存和消息处理能力。
515 79
|
4月前
|
供应链 JavaScript BI
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
这是一款专为小微企业打造的 SaaS ERP 管理系统,基于 SpringBoot+Vue+ElementUI+UniAPP 技术栈开发,帮助企业轻松上云。系统覆盖进销存、采购、销售、生产、财务、品质、OA 办公及 CRM 等核心功能,业务流程清晰且操作简便。支持二次开发与商用,提供自定义界面、审批流配置及灵活报表设计,助力企业高效管理与数字化转型。
442 2
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
|
4月前
|
缓存 Java 数据库
SpringBoot集成Ehcache缓存使用指南
以上是SpringBoot集成Ehcache缓存的基本操作指南,帮助你在实际项目中轻松实现缓存功能。当然,Ehcache还有诸多高级特性,通过学习和实践,你可以更好地发挥它的威力。
452 20
|
3月前
|
Java API 微服务
Java 21 与 Spring Boot 3.2 微服务开发从入门到精通实操指南
《Java 21与Spring Boot 3.2微服务开发实践》摘要: 本文基于Java 21和Spring Boot 3.2最新特性,通过完整代码示例展示了微服务开发全流程。主要内容包括:1) 使用Spring Initializr初始化项目,集成Web、JPA、H2等组件;2) 配置虚拟线程支持高并发;3) 采用记录类优化DTO设计;4) 实现JPA Repository与Stream API数据访问;5) 服务层整合虚拟线程异步处理和结构化并发;6) 构建RESTful API并使用Springdoc生成文档。文中特别演示了虚拟线程配置(@Async)和StructuredTaskSco
385 0