Spring Boot 缓存

Spring Framework 在 Spring 应用程序中提供了透明的缓存支持。在 Spring 中,缓存抽象是一种机制,它允许以最小的代码影响在各种缓存方法之间保持一致的使用方式。

缓存抽象机制适用于Java 方法。使用缓存抽象的主要目标是基于缓存中的信息减少执行次数。它适用于计算密集型或 I/O 密集型等昂贵的方法。

每次方法调用时,抽象会将缓存行为应用于该方法。它会检查该方法是否已对给定参数执行过。

  • 如果是,则返回缓存的结果,而不执行实际方法。
  • 如果不是,则首先执行方法,将结果缓存并返回给用户。

注意:此方法仅适用于保证对于给定输入会返回相同结果的方法。方法执行次数无关紧要。

在使用缓存抽象时,开发人员需要注意两件事情:

  • 缓存声明: 标识需要缓存的方法。
  • 缓存配置: 数据存储和读取的后备缓存。

缓存

缓存是临时内存的一部分。它位于应用程序和持久性数据库之间。它存储最近使用的数据,从而尽量减少对数据库的访问次数。换句话说,缓存是为了将数据存储以备将来使用。

为什么我们应该使用缓存?

使用缓存的主要原因是使数据访问更快速、更经济。当高度请求的资源被多次请求时,开发人员通常会将资源缓存在内存中,以便能够快速响应。在应用程序中使用缓存会提升应用程序的性能。从内存中访问数据与从数据库中检索数据相比,速度更快。它可以减少货币成本和机会成本。

哪些数据应该被缓存?

  • 不经常变化的数据。
  • 经常使用的读取查询,在每次调用中结果都不会改变,至少在一段时间内不会改变。

缓存的类型

有四种缓存类型,如下所示:

  • 内存中的缓存
  • 数据库缓存
  • Web 服务器缓存
  • CDN 缓存

内存中的缓存

内存中的缓存可以提高应用程序的性能。它是经常使用的区域。MemcachedRedis 是内存中缓存的示例。它在应用程序和数据库之间存储键值对。Redis 是一种内存中分布式的高级缓存工具,可以进行备份和还原。我们可以在分布式集群中管理缓存。

数据库缓存

数据库缓存是一种动态生成 Web 页面的机制,它通过从数据库中获取数据来实现(动态生成)。它在涉及客户端、Web 应用程序服务器和数据库的多层环境中使用。通过分发查询负载,它提高了可扩展性性能。最流行的数据库缓存是的一级缓存。

Web 服务器缓存

Web 服务器缓存是一种存储数据以供重复使用的机制。例如,由 Web 服务器提供的网页的副本。当用户首次访问页面时,它会被缓存。如果用户下次请求相同的页面,缓存会提供一个页面的副本。这样可以避免服务器过载。Web 服务器缓存可以提高页面传递速度,减少后端服务器的负载。

CDN 缓存

CDN 代表内容传递网络。它是现代 Web 应用程序中使用的一个组件。它通过在全球分布的缓存服务器集合复制常用请求的文件(例如 HTML 页面、样式表、JavaScript、图像、视频等)来改进内容的传递。

这就是 CDN 变得更加流行的原因。CDN 减少了应用程序源的负载,提高了用户体验。它从附近的缓存边缘(靠近终端用户的缓存服务器)或Point of Presence (PoP) 提供内容的本地副本。

缓存与缓冲区的区别

缓存缓冲区
缓存基于最近最少使用(LRU)缓冲区基于先进先出(FIFO)
它的大小是页面缓存的大小。它是一个内存中的原始块 I/O 缓冲区。
它的生命周期较长。它的生命周期较短。
我们从缓存中读取我们写入缓冲区。
它存储实际文件数据。它存储文件的元数据
它提高了读取性能。它提高了写入性能。

Spring Boot 缓存注解

@EnableCaching 这是一个类级别的注解。我们可以通过使用注解@EnableCaching在Spring Boot应用程序中启用缓存。它位于org.springframework.cache.annotation包中。它通常与@Configuration类一起使用。

自动配置会启用缓存并设置CacheManager,如果没有已定义的CacheManager实例。它会扫描特定的提供程序,当找不到时,它会使用并发HashMap创建一个内存中的缓存。

示例

在以下示例中,@EnableCaching注解启用了缓存机制。

@SpringBootApplication  
@EnableCaching   
public class SpringBootCachingApplication   
{  
public static void main(String[] args)   
{  
SpringApplication.run(SpringBootCachingApplication.class, args);  
}  
}  

@CacheConfig 这是一个类级别的注解,提供了通用的与缓存相关的设置。它告诉Spring在哪里为类存储缓存。当我们使用该注解注释一个类时,它为该类中定义的任何缓存操作提供一组默认设置。使用该注解,我们不需要多次声明相同的内容。

示例

在以下示例中,employee是缓存的名称。

@CacheConfig(cacheNames={"employee"})   
public class UserService  
{  
//some code  
}  

@Caching 当我们在同一个方法上需要同时使用@CachePut或@CacheEvict注解时,可以使用@Caching注解。换句话说,当我们想要使用相同类型的多个注解时,可以使用@Caching注解。

但是Java不允许为给定方法声明多个相同类型的注解。为了避免这个问题,我们使用@Caching注解。

示例

在以下示例中,我们使用了@Caching注解,将所有的@CacheEvict注解分组在一起。

@Caching(evict = {@CacheEvict("phone_number"), @CacheEvict(value="directory", key="#student.id") })  
public String getAddress(Student student)   
{  
//some code  
}  

@Cacheable 这是一个方法级别的注解,它为方法的返回值定义了一个缓存。Spring Framework会将方法的请求和响应管理到在注解属性中指定的缓存中。@Cacheable注解包含更多选项。例如,我们可以使用value或cacheNames属性来提供缓存名称。

我们还可以通过使用注解的key属性来指定唯一标识缓存中每个条目。如果不指定key,Spring将使用默认机制创建key。

示例

在以下示例中,我们在名为cacheStudentInfo的缓存中缓存了方法studentInfo()的返回值,id是唯一标识缓存中每个条目的键。

@Cacheable(value="cacheStudentInfo", key="#id")  
public List studentInfo()  
{  
//some code   
return studentDetails;  
}  

我们还可以在注解中使用条件,通过使用condition属性。当我们在注解中应用条件时,称为条件缓存。

例如,如果参数name的长度小于20,则下面的方法将被缓存。

@Cacheable(value="student", condition="#name.length<20")  
public Student findStudent(String name)  
{  
//some code  
}  

@CacheEvict 这是一个方法级别的注解。当我们想要从缓存中删除陈旧或未使用的数据时,使用它。它需要一个或多个受操作影响的缓存。我们还可以在其中指定key或条件。如果我们想要广泛地清除缓存,@CacheEvict注解提供了一个名为allEntries的参数。它会清除所有条目,而不是基于key清除一个条目。

关于@CacheEvict注解的一个重要点是它可以与void方法一起使用,因为该方法作为触发器。它避免了返回值。另一方面,@Cacheable注解需要一个返回值,将数据添加/更新到缓存中。我们可以以下几种方式使用@CacheEvict注解:

清除整个缓存:

@CacheEvict(allEntries=true)  

根据键清除条目:

@CacheEvict(key="#student.stud_name")  

示例

以下带有注解的方法会从缓存student_data中清除所有数据。

@CacheEvict(value="student_data", allEntries=true) //removing all entries from the cache  
public String getNames(Student student)   
{  
//some code  
}  

@CachePut 这是一个方法级别的注解。当我们希望在不干扰方法执行的情况下更新缓存时,可以使用它。这意味着该方法将始终执行,并将其结果放入缓存中。它支持@Cacheable注解的属性。

需要注意的一点是,@Cacheable和@CachePut注解不同,因为它们具有不同的行为。@Cacheable注解会跳过方法执行,而@CachePut注解会运行方法并将结果放入缓存中。

示例

以下方法将更新缓存本身。

@CachePut(cacheNames="employee", key="#id") //updating cache  
public Employee updateEmp(ID id, EmployeeData data)  
{  
//some code  
}  

Spring Boot 缓存依赖 如果我们想要在Spring Boot应用程序中启用缓存机制,需要在pom.xml文件中添加缓存依赖。它将启用缓存并配置CacheManager。

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

Spring Boot 缓存示例 让我们创建一个Spring Boot应用程序,并将缓存机制实现其中。

步骤1:打开Spring Initializr http://start.spring.io。

步骤2:选择Spring Boot版本2.3.0.M1。

步骤3:提供组名。我们提供了cn.javatiku。

步骤4:提供Artifact Id。我们提供了spring-boot-cache-example。

步骤5:添加Spring Web和Spring Cache Abstraction依赖项。

步骤6:点击Generate按钮。点击Generate按钮后,它将规范包装到一个Jar文件中,并将其下载到本地系统。

步骤7:解压缩Jar文件,并将其粘贴到STS工作区。

步骤8:在STS中导入项目文件夹。

File -> Import -> Existing Maven Projects -> Browse -> 选择文件夹spring-boot-cache-example -> 完成

导入需要一些时间。

让我们打开pom.xml文件,看看我们添加了哪些依赖项。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>  
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">  
    <modelVersion>4.0.0</modelVersion>  
    <parent>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-parent</artifactId>  
        <version>2.3.0.M1</version>  
        <relativePath/> <!-- lookup parent from repository -->  
    </parent>  
    <groupId>cn.javatiku</groupId>  
    <artifactId>spring-boot-cache-example</artifactId>  
    <version>0.0.1-SNAPSHOT</version>  
    <name>spring-boot-cache-example</name>  
    <description>Demo project for Spring Boot</description>  
    <properties>  
        <java.version>1.8</java.version>  
    </properties>  
    <dependencies>  
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-cache</artifactId>  
        </dependency>  
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-web</artifactId>  
        </dependency>  
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-test</artifactId>  
            <scope>test</scope>  
            <exclusions>  
                <exclusion>  
                    <groupId>org.junit.vintage</groupId>  
                    <artifactId>junit-vintage-engine</artifactId>  
                </exclusion>  
            </exclusions>  
        </dependency>  
    </dependencies>  
    <build>  
        <plugins>  
            <plugin>  
                <groupId>org.springframework.boot</groupId>  
                <artifactId>spring-boot-maven-plugin</artifactId>  
            </plugin>  
        </plugins>  
    </build>  
    <repositories>  
        <repository>  
            <id>spring-milestones</id>  
            <name>Spring Milestones</name>  
            <url>https://repo.spring.io/milestone</url>  
        </repository>  
    </repositories>  
    <pluginRepositories>  
        <pluginRepository>  
            <id>spring-milestones</id>  
            <name>Spring Milestones</name>  
            <url>https://repo.spring.io/milestone</url>  
        </pluginRepository>  
    </pluginRepositories>  
</project>  

步骤9:打开SpringBootCacheExampleApplication.java文件,并通过添加@EnableCaching注解来启用缓存。

SpringBootCacheExampleApplication.java

SpringBootCacheExampleApplication.java  
package cn.javatiku;  
import org.springframework.boot.SpringApplication;  
import org.springframework.boot.autoconfigure.SpringBootApplication;  
import org.springframework.cache.annotation.EnableCaching;  
@SpringBootApplication  
//enabling caching  
@EnableCaching  
public class SpringBootCacheExampleApplication   
{  
public static void main(String[] args)   
{  
SpringApplication.run(SpringBootCacheExampleApplication.class, args);  
}  
}  

步骤10:在src/main/java文件夹中创建一个名为cn.javatiku.model的包。

步骤11:在model包中,创建一个名为Customer的类,并定义以下内容:

  • 定义三个变量accountno、customername、acounttype和balance。
  • 使用字段生成构造函数。
  • 右键单击文件 -> Source -> Generate Constructor using Fields -> 选择全部 -> 生成
  • 生成Getters和Setters。
  • 右键单击文件 -> Source -> Generate Getters and Setters -> 选择全部 -> 生成

Customer.java

package cn.javatiku.model;  
public class Customer   
{  
private int accountno;  
private String customername;  
private String accounttype;  
private double balance;  
public Customer(int accountno, String customername, String accounttype, double balance)   
{  
this.accountno = accountno;  
this.customername = customername;  
this.accounttype = accounttype;  
this.balance = balance;  
}  
public int getAccountno()   
{  
return accountno;  
}  
public void setAccountno(int accountno)   
{  
this.accountno = accountno;  
}  
public String getCustomername()   
{  
return customername;  
}  
public void setCustomername(String customername)   
{  
this.customername = customername;  
}  
public String getAccounttype()   
{  
return accounttype;  
}  
public void setAccounttype(String accounttype)   
{  
this.accounttype = accounttype;  
}  
public double getBalance()   
{  
return balance;  
}  
public void setBalance(double balance)   
{  
this.balance = balance;  
}  
}  

步骤11:在src/main/java文件夹中创建一个名为cn.javatiku.controller的包。

步骤12:在Controller包中,创建一个名为CustomerController的控制器类,并执行以下操作:

  • 使用注解@RestController将类标记为控制器。
  • 使用注解@RequestMapping为控制器定义映射。我们定义了映射/customerinfo。
  • 通过使用@Cacheable注解创建一个缓存,用于获取数据。我们使用注解的value属性定义了缓存名称。
  • 我们在customerInformation方法中添加了两个客户细节。

CustomerController.java

package cn.javatiku.controller;  
import java.util.Arrays;  
import java.util.List;  
import org.springframework.cache.annotation.Cacheable;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.RestController;  
import cn.javatiku.model.Customer;  
@RestController  
public class CustomerController   
{  
@RequestMapping("/customerinfo")  
//defines a cache for method's return value  
@Cacheable(value="customerInfo")  
public List customerInformation()  
{  
System.out.println("customer information from cache");  
//adding customer detail in the List  
    List detail=Arrays.asList(new Customer(5126890,"Charlie Puth","Current A/c", 450000.00),  
                              new Customer(7620015,"Andrew Flintoff","Saving A/c", 210089.00)  
                             );  
return detail;  
}  
}  

现在运行应用程序。

步骤13:打开SpringBootCacheExampleApplication.java文件,并将其运行为Java应用程序。

步骤14:打开Postman,并发送一个GET请求,URL为http://locahost:8080/customerinfo。它会返回客户详细信息,如下所示。
545b4ab36bd6a2490f5b9f224ec2137.png

标签: spring, Spring教程, Spring语言学习, Spring框架, Spring框架教程, Spring框架高级教程, spring boot, spring boot入门教程, spring boot学习教程, spring boot下载, spring boot框架入门, spring boot面试题, spring boot笔试题, spring boot学习指南, spring boot技术