package com.example.caching;
public class Book {
private String isbn;
private String title;
public Book(String isbn, String title) {
this.isbn = isbn;
this.title = title;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@Override
public String toString() {
return "Book{" + "isbn='" + isbn + '\'' + ", title='" + title + '\'' + '}';
}
}
使用 Spring 快取資料
本指南將引導您完成在 Spring 管理的 bean 上啟用快取的過程。
您將構建什麼
您將構建一個在簡單書籍倉庫上啟用快取的應用。
您需要什麼
-
大約 15 分鐘
-
一個您喜歡的文字編輯器或 IDE
-
Java 17 或更高版本
-
您也可以將程式碼直接匯入到您的 IDE 中
如何完成本指南
與大多數 Spring 入門指南類似,您可以從零開始完成每個步驟,也可以跳過您已經熟悉的基本設定步驟。無論哪種方式,您最終都會得到可工作的程式碼。
要從零開始,請繼續閱讀從 Spring Initializr 開始。
要跳過基礎部分,請執行以下操作
-
下載並解壓本指南的原始碼倉庫,或使用 Git 克隆它:
git clone https://github.com/spring-guides/gs-caching.git
-
cd 進入
gs-caching/initial
-
跳到建立 Book 模型。
完成後,您可以根據 gs-caching/complete
中的程式碼檢查您的結果。
從 Spring Initializr 開始
您可以使用這個預初始化的專案,然後點選 Generate 下載 ZIP 檔案。該專案配置適用於本教程中的示例。
手動初始化專案
-
導航到 https://start.spring.io。此服務會拉取應用所需的所有依賴項,併為您完成大部分設定。
-
選擇 Gradle 或 Maven 以及您想使用的語言。本指南假設您選擇了 Java。
-
點選 Dependencies,然後選擇 Spring cache abstraction。
-
點選 Generate。
-
下載生成的 ZIP 檔案,它是一個根據您的選擇配置好的 Web 應用壓縮包。
如果您的 IDE 集成了 Spring Initializr,您可以直接在 IDE 中完成此過程。 |
您也可以從 Github fork 該專案,然後在您的 IDE 或其他編輯器中開啟它。 |
建立 Book 模型
首先,您需要為您的書建立一個簡單的模型。以下清單(來自 src/main/java/com/example/caching/Book.java
)展示瞭如何實現
建立 Book 倉庫
您還需要一個該模型的倉庫。以下清單(來自 src/main/java/com/example/caching/BookRepository.java
)展示了這樣的倉庫
package com.example.caching;
public interface BookRepository {
Book getByIsbn(String isbn);
}
您可以使用 Spring Data 為您的倉庫提供基於各種 SQL 或 NoSQL 儲存的實現。然而,出於本指南的目的,您將只使用一個簡單的實現來模擬一些延遲(網路服務、慢速延遲或其他問題)。以下清單(來自 src/main/java/com/example/caching/SimpleBookRepository.java
)展示了這樣的倉庫
package com.example.caching;
import org.springframework.stereotype.Component;
@Component
public class SimpleBookRepository implements BookRepository {
@Override
public Book getByIsbn(String isbn) {
simulateSlowService();
return new Book(isbn, "Some book");
}
// Don't do this at home
private void simulateSlowService() {
try {
long time = 3000L;
Thread.sleep(time);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
}
simulateSlowService
方法故意在每次呼叫 getByIsbn
時插入三秒延遲。稍後,您將透過快取來加速此示例。
使用倉庫
接下來,您需要連線倉庫並使用它來訪問一些書籍。以下清單(來自 src/main/java/com/example/caching/CachingApplication.java
)展示瞭如何實現
package com.example.caching;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CachingApplication {
public static void main(String[] args) {
SpringApplication.run(CachingApplication.class, args);
}
}
@SpringBootApplication
是一個方便的註解,它添加了以下所有內容
-
@Configuration
:將類標記為應用上下文的 bean 定義源。 -
@EnableAutoConfiguration
:告訴 Spring Boot 根據 classpath 設定、其他 bean 和各種屬性設定開始新增 bean。例如,如果 classpath 中有spring-webmvc
,則此註解會將應用標記為 Web 應用並激活關鍵行為,例如設定DispatcherServlet
。 -
@ComponentScan
:告訴 Spring 在com/example
包中查詢其他元件、配置和服務,從而找到控制器。
main()
方法使用 Spring Boot 的 SpringApplication.run()
方法啟動應用。您注意到沒有一行 XML 嗎?也沒有 web.xml
檔案。這個 Web 應用是 100% 純 Java 的,您無需處理任何底層或基礎設施的配置。
您還需要一個 CommandLineRunner
,它注入 BookRepository
並使用不同的引數多次呼叫它。以下清單(來自 src/main/java/com/example/caching/AppRunner.java
)展示了該類
package com.example.caching;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class AppRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(AppRunner.class);
private final BookRepository bookRepository;
public AppRunner(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
@Override
public void run(String... args) throws Exception {
logger.info(".... Fetching books");
logger.info("isbn-1234 -->" + bookRepository.getByIsbn("isbn-1234"));
logger.info("isbn-4567 -->" + bookRepository.getByIsbn("isbn-4567"));
logger.info("isbn-1234 -->" + bookRepository.getByIsbn("isbn-1234"));
logger.info("isbn-4567 -->" + bookRepository.getByIsbn("isbn-4567"));
logger.info("isbn-1234 -->" + bookRepository.getByIsbn("isbn-1234"));
logger.info("isbn-1234 -->" + bookRepository.getByIsbn("isbn-1234"));
}
}
如果您此時嘗試執行該應用,您應該會注意到它相當慢,即使您多次檢索完全相同的書。以下示例輸出顯示了我們的(故意寫的糟糕的)程式碼造成的三秒延遲
2014-06-05 12:15:35.783 ... : .... Fetching books 2014-06-05 12:15:40.783 ... : isbn-1234 -->Book{isbn='isbn-1234', title='Some book'} 2014-06-05 12:15:43.784 ... : isbn-1234 -->Book{isbn='isbn-1234', title='Some book'} 2014-06-05 12:15:46.786 ... : isbn-1234 -->Book{isbn='isbn-1234', title='Some book'}
我們可以透過啟用快取來改善這種情況。
啟用快取
現在您可以在 SimpleBookRepository
上啟用快取,以便將書籍快取在 books
快取中。以下清單(來自 src/main/java/com/example/caching/SimpleBookRepository.java
)展示了倉庫定義
package com.example.caching;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
@Component
public class SimpleBookRepository implements BookRepository {
@Override
@Cacheable("books")
public Book getByIsbn(String isbn) {
simulateSlowService();
return new Book(isbn, "Some book");
}
// Don't do this at home
private void simulateSlowService() {
try {
long time = 3000L;
Thread.sleep(time);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
}
現在您需要啟用快取註解的處理,如下例(來自 src/main/java/com/example/caching/CachingApplication.java
)所示
package com.example.caching;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class CachingApplication {
public static void main(String[] args) {
SpringApplication.run(CachingApplication.class, args);
}
}
透過 @EnableCaching
註解會觸發一個後置處理器,該處理器檢查每個 Spring bean 的公共方法是否存在快取註解。如果找到此類註解,會自動建立一個代理來攔截方法呼叫並相應地處理快取行為。
後置處理器會處理 @Cacheable
、@CachePut
和 @CacheEvict
註解。您可以查閱 Javadoc 和 參考指南瞭解更多詳情。
Spring Boot 會自動配置合適的 CacheManager
作為相關快取的提供者。更多詳情請參閱 Spring Boot 文件。
我們的示例沒有使用特定的快取庫,所以我們的快取儲存是使用 ConcurrentHashMap
的簡單回退方案。快取抽象支援多種快取庫,並且完全相容 JSR-107 (JCache)。
構建可執行 JAR
您可以使用 Gradle 或 Maven 從命令列執行應用。您也可以構建一個包含所有必要依賴項、類和資源的可執行 JAR 檔案並執行它。構建可執行 JAR 可以輕鬆地在整個開發生命週期中、跨不同環境等情況下,將服務作為應用進行交付、版本控制和部署。
如果您使用 Gradle,可以使用 ./gradlew bootRun
執行應用。或者,您可以使用 ./gradlew build
構建 JAR 檔案,然後按如下方式執行 JAR 檔案
如果您使用 Maven,可以使用 ./mvnw spring-boot:run
執行應用。或者,您可以使用 ./mvnw clean package
構建 JAR 檔案,然後按如下方式執行 JAR 檔案
此處描述的步驟建立了一個可執行的 JAR。您還可以構建一個經典的 WAR 檔案。 |
測試應用
現在快取已啟用,您可以再次執行應用,透過新增使用或不使用相同 ISBN 的額外呼叫來檢視差異。這應該會產生巨大影響。以下清單顯示了啟用快取後的輸出
2016-09-01 11:12:47.033 .. : .... Fetching books 2016-09-01 11:12:50.039 .. : isbn-1234 -->Book{isbn='isbn-1234', title='Some book'} 2016-09-01 11:12:53.044 .. : isbn-4567 -->Book{isbn='isbn-4567', title='Some book'} 2016-09-01 11:12:53.045 .. : isbn-1234 -->Book{isbn='isbn-1234', title='Some book'} 2016-09-01 11:12:53.045 .. : isbn-4567 -->Book{isbn='isbn-4567', title='Some book'} 2016-09-01 11:12:53.045 .. : isbn-1234 -->Book{isbn='isbn-1234', title='Some book'} 2016-09-01 11:12:53.045 .. : isbn-1234 -->Book{isbn='isbn-1234', title='Some book'}
在前面的示例輸出中,第一次檢索書籍仍然需要三秒鐘。然而,對於同一本書的第二次和後續檢索則快得多,這表明快取正在發揮作用。
總結
恭喜!您剛剛在 Spring 管理的 bean 上啟用了快取。