Spring boot教程-Spring Boot 缓存
Spring Boot 缓存
Spring Framework 在 Spring 应用程序中提供了透明的缓存支持。在 Spring 中,缓存抽象是一种机制,它允许以最小的代码影响在各种缓存方法之间保持一致的使用方式。
缓存抽象机制适用于Java 方法。使用缓存抽象的主要目标是基于缓存中的信息减少执行次数。它适用于计算密集型或 I/O 密集型等昂贵的方法。
每次方法调用时,抽象会将缓存行为应用于该方法。它会检查该方法是否已对给定参数执行过。
- 如果是,则返回缓存的结果,而不执行实际方法。
- 如果不是,则首先执行方法,将结果缓存并返回给用户。
注意:此方法仅适用于保证对于给定输入会返回相同结果的方法。方法执行次数无关紧要。
在使用缓存抽象时,开发人员需要注意两件事情:
- 缓存声明: 标识需要缓存的方法。
- 缓存配置: 数据存储和读取的后备缓存。
缓存
缓存是临时内存的一部分。它位于应用程序和持久性数据库之间。它存储最近使用的数据,从而尽量减少对数据库的访问次数。换句话说,缓存是为了将数据存储以备将来使用。
为什么我们应该使用缓存?
使用缓存的主要原因是使数据访问更快速、更经济。当高度请求的资源被多次请求时,开发人员通常会将资源缓存在内存中,以便能够快速响应。在应用程序中使用缓存会提升应用程序的性能。从内存中访问数据与从数据库中检索数据相比,速度更快。它可以减少货币成本和机会成本。
哪些数据应该被缓存?
- 不经常变化的数据。
- 经常使用的读取查询,在每次调用中结果都不会改变,至少在一段时间内不会改变。
缓存的类型
有四种缓存类型,如下所示:
- 内存中的缓存
- 数据库缓存
- Web 服务器缓存
- CDN 缓存
内存中的缓存
内存中的缓存可以提高应用程序的性能。它是经常使用的区域。Memcached 和 Redis 是内存中缓存的示例。它在应用程序和数据库之间存储键值对。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
。它会返回客户详细信息,如下所示。