Spring框架透明地在Spring應(yīng)用程序中提供緩存。在Spring中,緩存抽象是一種機(jī)制,它允許在不影響代碼的情況下一致使用各種緩存方法。
緩存抽象機(jī)制適用于 Java 方法。使用緩存抽象的主要目的是根據(jù)緩存中存在的信息減少執(zhí)行次數(shù)。它適用于昂貴的方法,例如 CPU 或 IO綁定。
每次調(diào)用方法時(shí),抽象都會(huì)將緩存行為應(yīng)用于該方法。它檢查該方法是否已經(jīng)針對(duì)給定參數(shù)執(zhí)行。
如果是,則不執(zhí)行實(shí)際方法就返回緩存的結(jié)果。如果否,則首先執(zhí)行該方法,并將結(jié)果緩存并返回給用戶。
開發(fā)人員在處理緩存抽象時(shí)會(huì)注意兩件事。
緩存聲明: 它標(biāo)識(shí)需要緩存的方法。 緩存配置: 用于存儲(chǔ)和讀取數(shù)據(jù)的后備緩存。
緩存是臨時(shí)內(nèi)存的一部分( RAM )。它位于應(yīng)用程序和持久性數(shù)據(jù)庫之間。它存儲(chǔ)最近使用的數(shù)據(jù),從而盡可能減少數(shù)據(jù)庫命中次數(shù)。換句話說,緩存是為了存儲(chǔ)數(shù)據(jù)以供將來參考。
使用緩存的主要原因是為了進(jìn)行數(shù)據(jù)訪問更快,更便宜。當(dāng)多次請(qǐng)求高度請(qǐng)求的資源時(shí),對(duì)于開發(fā)人員來說,緩存資源通常是有益的,這樣它可以快速給出響應(yīng)。在應(yīng)用程序中使用緩存可以增強(qiáng)應(yīng)用程序的性能。與從數(shù)據(jù)庫中獲取數(shù)據(jù)相比,從內(nèi)存進(jìn)行數(shù)據(jù)訪問總是更快。它降低了貨幣成本和機(jī)會(huì)成本。
不經(jīng)常更改的數(shù)據(jù)。經(jīng)常使用的讀取查詢,其查詢結(jié)果在每個(gè)調(diào)用中至少一段時(shí)間沒有變化。
有四種緩存類型如下:
內(nèi)存中緩存數(shù)據(jù)庫緩存 Web服務(wù)器緩存 CDN緩存
內(nèi)存緩存可提高應(yīng)用程序的性能。這是經(jīng)常使用的區(qū)域。 Memcached 和 Redis 是內(nèi)存中緩存的示例。它在應(yīng)用程序和數(shù)據(jù)庫之間存儲(chǔ)鍵值。 Redis是一種內(nèi)存中,分布式高級(jí)緩存工具,可用于備份和還原功能。我們還可以管理分布式集群中的緩存。
數(shù)據(jù)庫緩存是一種通過獲取數(shù)據(jù)按需(動(dòng)態(tài))生成網(wǎng)頁的機(jī)制。從數(shù)據(jù)庫中。它在涉及客戶端,Web應(yīng)用程序服務(wù)器和數(shù)據(jù)庫的多層環(huán)境中使用。通過分配查詢工作負(fù)載,它提高了可擴(kuò)展性和性能。最受歡迎的數(shù)據(jù)庫緩存是 Hibernate 的一級(jí)緩存。
Web服務(wù)器緩存是一種存儲(chǔ)數(shù)據(jù)以便重用的機(jī)制。例如,由Web服務(wù)器提供的網(wǎng)頁的副本。用戶首次訪問該頁面時(shí)將對(duì)其進(jìn)行緩存。如果用戶下次再次請(qǐng)求相同的內(nèi)容,則緩存將提供頁面的副本。這樣可以避免服務(wù)器表單過載。 Web服務(wù)器緩存可提高頁面交付速度,并減少后端服務(wù)器要做的工作。
CDN 代表內(nèi)容交付網(wǎng)絡(luò)。它是現(xiàn)代Web應(yīng)用程序中使用的組件。通過復(fù)制常用文件(例如 HTML 頁面,樣式表),它可以改善內(nèi)容的傳遞。 , JavaScript ,圖像,視頻等)分布在一組全球分布的緩存服務(wù)器上。
這是CDN越來越受歡迎的原因。 CDN減輕了應(yīng)用程序源的負(fù)擔(dān),并改善了用戶體驗(yàn)。它從附近的緩存邊緣(更靠近最終用戶的緩存服務(wù)器)或存在點(diǎn)(PoP)提供內(nèi)容的本地副本。
緩存 | 緩沖區(qū) |
緩存基于最近最少使用。 | 緩沖區(qū)基于先進(jìn)先出 |
它是頁面緩存的大小。 | 它是內(nèi)存中的原始?jí)KI/O緩沖區(qū)。 |
它生存了很長時(shí)期。 | 它生存了短時(shí)期。 |
我們從緩存中讀取。 | 我們寫入到緩沖區(qū)。 |
它存儲(chǔ)實(shí)際文件數(shù)據(jù)。 | 它存儲(chǔ)文件元數(shù)據(jù)。 |
它提高了 read 性能。 | 它提高了寫入性能。 |
這是一個(gè)類級(jí)別的注解。我們可以通過使用 @EnableCaching注解在Spring Boot應(yīng)用程序中啟用緩存。它在 org.springframework.cache.annotation 包中定義。它與 @Configuration 類一起使用。
如果沒有已定義的CacheManager實(shí)例,自動(dòng)配置將啟用緩存并設(shè)置 CacheManager 。它會(huì)掃描特定的提供程序,如果找不到,則會(huì)使用并發(fā)的 HashMap創(chuàng)建內(nèi)存中緩存。
示例
在以下示例中, @EnableCaching 注解啟用了緩存機(jī)制。
@SpringBootApplication @EnableCaching public class SpringBootCachingApplication { public static void main(String[] args) { SpringApplication.run(SpringBootCachingApplication.class, args); } }
這是一個(gè)類級(jí)別的注解,提供了與緩存有關(guān)的通用設(shè)置。它告訴Spring將類的緩存存儲(chǔ)在何處。當(dāng)我們使用注解為類添加注解時(shí),它為該類中定義的任何緩存操作提供了一組默認(rèn)設(shè)置。使用注解,我們不需要多次聲明。
示例
在下面的示例中,員工是緩存的名稱。
@CacheConfig(cacheNames={"employee"}) public class UserService { //some code }
當(dāng)我們同時(shí)需要兩個(gè)注解 @CachePut 或 @CacheEvict 時(shí)使用同樣的方法。換句話說,當(dāng)我們要使用相同類型的多個(gè)注解時(shí)使用。
但是 Java不允許為給定聲明相同類型的多個(gè)注解方法。為避免此問題,我們使用 @Caching 注解。
示例
在下面的示例中,我們使用了注解 @Caching 并將所有 @CacheEvict 注解分組。
@Caching(evict = {@CacheEvict("phone_number"), @CacheEvict(value="directory", key="#student.id") })public String getAddress(Student student) { //some code }
它是方法級(jí)別的注解。它為方法的返回值定義了一個(gè)緩存。 Spring框架管理方法對(duì)注解屬性中指定的緩存的請(qǐng)求和響應(yīng)。 @Cacheable批注包含更多選項(xiàng)。例如,我們可以使用 value 或 cacheNames 屬性提供緩存名稱。
我們還可以指定注解的 key 屬性,用于唯一標(biāo)識(shí)緩存中的每個(gè)條目。如果未指定密鑰,Spring將使用默認(rèn)機(jī)制來創(chuàng)建密鑰。
示例
在以下示例中,我們緩存了< cacheStudentInfo,和 id 中方法 studentInfo()的strong>返回值是唯一鍵,用于標(biāo)識(shí)緩存。
@Cacheable(value="cacheStudentInfo", key="#id")public List studentInfo() { //some code return studentDetails; }
我們還可以通過使用condition屬性在注解中應(yīng)用條件。當(dāng)我們?cè)谧⒔庵袘?yīng)用條件時(shí),它稱為條件緩存。
例如,如果參數(shù)名稱的長度短于20,則將緩存以下方法。
@Cacheable(value="student", condition="#name.length<20")public Student findStudent(String name) { //some code }
它是方法級(jí)別的注解。當(dāng)我們想要從緩存中刪除陳舊或未使用的數(shù)據(jù)時(shí),將使用它。它需要一個(gè)或多個(gè)受操作影響的緩存。我們還可以在其中指定鍵或條件。如果我們想要廣泛的緩存驅(qū)逐,則@CacheEvict批注提供一個(gè)名為 allEntries 的參數(shù)。它會(huì)驅(qū)逐所有條目,而不是根據(jù)密鑰驅(qū)逐一個(gè)條目。
關(guān)于@CacheEvict批注的重要一點(diǎn)是它可以與void方法一起使用,因?yàn)樵摲椒ǔ洚?dāng)觸發(fā)器。它避免了返回值。另一方面,@Cacheable批注需要一個(gè)返回值,該值用于添加/更新緩存中的數(shù)據(jù)。我們可以通過以下方式使用@CacheEvict批注:
逐出整個(gè)緩存:
@CacheEvict(allEntries=true)
通過密鑰逐出條目:
@CacheEvict(key="#student.stud_name")
示例
以下帶注解的方法從緩存 student_data 中清除所有數(shù)據(jù)。
@CacheEvict(value="student_data", allEntries=true) //removing all entries from the cache public String getNames(Student student) { //some code }
它是方法級(jí)別的注解。當(dāng)我們想要更新緩存而不干擾方法執(zhí)行時(shí),使用它。這意味著該方法將始終執(zhí)行,并將其結(jié)果放入緩存中。它支持@Cacheable批注的屬性。
需要注意的是,由于@Cacheable和@CachePut批注的行為不同,因此它們是不相同的。 @Cacheable和@CachePut批注之間存在細(xì)微差別,就是@ Cacheable 批注跳過方法執(zhí)行,而 @CachePut 批注運(yùn)行該方法,然后將結(jié)果放入緩存。
示例
以下方法將更新緩存本身。
@CachePut(cacheNames="employee", key="#id") //updating cachepublic Employee updateEmp(ID id, EmployeeData data) { //some code }
如果要在Spring Boot應(yīng)用程序中啟用緩存機(jī)制,則需要在pom.xml文件中添加緩存依賴項(xiàng)。它啟用緩存并配置CacheManager。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
我們創(chuàng)建一個(gè)Spring Boot應(yīng)用程序并在其中實(shí)現(xiàn)緩存機(jī)制。
步驟1: 打開Spring Initializr http://start.spring.io 。
步驟2: 選擇Spring Boot版本 2.3.0.M1。
步驟2: 提供群組名稱。我們提供了 com.nhooo。
步驟3: 提供工件 ID。我們提供了 spring-boot-cache-example。
步驟5: 添加依賴項(xiàng) Spring Web 和 Spring Cache抽象。
步驟6: 單擊 Generate (生成)按鈕。當(dāng)我們單擊"生成"按鈕時(shí),它將規(guī)格包裝在 Jar 文件中,并將其下載到本地系統(tǒng)。
步驟7: 提取 Jar文件并將其粘貼到STS工作區(qū)中。
步驟8: 導(dǎo)入 STS中的項(xiàng)目文件夾。
文件->導(dǎo)入->現(xiàn)有Maven項(xiàng)目->瀏覽->選擇文件夾spring-boot-cache-example->完成
導(dǎo)入需要一些時(shí)間。
讓我們打開 pom.xml 文件,看看我們已經(jīng)向其中添加了哪些依賴項(xiàng)。
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>com.nhooo</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 package com.nhooo; 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: 在名為 com.nhooo.model的文件夾 src/main/java 中創(chuàng)建一個(gè)包。
步驟11: 在模型包中,創(chuàng)建一個(gè)名稱為 Customer 的類并定義以下內(nèi)容:
定義三個(gè)accountno, customername, acounttype和balance。使用Constructor生成構(gòu)造器 。
右鍵單擊文件->源->使用字段生成構(gòu)造器->全選->生成生成Getters and Setters。
右鍵單擊文件->源->生成Getter和設(shè)置器->全選->生成
Customer.java
package com.nhooo.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 中創(chuàng)建一個(gè)名稱為 com.nhooo.controller的包。
步驟12: 在Controller程序包中,創(chuàng)建一個(gè)名稱為 CustomerController 的控制器類,然后執(zhí)行以下操作:
使用注解 @RestController將類標(biāo)記為 Controller 。 使用注解 @RequestMapping為控制器定義映射。我們已經(jīng)定義了映射/customerinfo 。創(chuàng)建緩存以使用注解 @Cacheable獲取數(shù)據(jù)。 我們已經(jīng)通過使用注解的 value 屬性定義了緩存名稱。我們?cè)?/span>中添加了兩個(gè)客戶詳細(xì)信息
CustomerController.java
package com.nhooo.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 com.nhooo.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; } }
現(xiàn)在運(yùn)行該應(yīng)用程序。
步驟13: 打開 SpringBootCacheExampleApplication.java 文件并將其作為Java應(yīng)用程序運(yùn)行。
步驟14: 打開Postman,并發(fā)送帶有URL http: //locahost: 8080/custmerinfo的 GET 請(qǐng)求。它返回客戶詳細(xì)信息,如下所示。