最近貓哥在研究SpringBoot緩存,在這裏對SpringBoot的Ehcache2.x緩存做一個總結梳理,順便貼一下自己寫的實戰代碼,以供參考。
SpringBoot緩存
Spring3.1中開始對緩存提供支持,核心思路是對方法的緩存,當開發者調用一個方法時,將方法的參數和返回值作爲key/value緩存起來,當再次調用該方法時,如果緩存中有數據,就直接從緩存中獲取,否則再去執行該方法。但是,Spring中未提供緩存的實現,而是提供了一套緩存API,開發者可以自由選擇緩存的實現,目前SpringBoot支持的緩存有如下幾種:
- JCache(JSR-107)
- EnCache2.x
- Hazelcast
- Infinispan
- Couchbase
- Redis
- Caffeine
- Simple
這裏主要介紹目前常用的緩存實現之一:EnCache2.x。由於Spring早已將緩存領域統一,因此無論使用哪種緩存實現,不同的只是緩存配置,開發者使用的緩存註解是一致的。
EnCache2.x緩存
在SpringBoot中,EnCache2.x緩存的使用十分常見,實現也比較容易,只需一個配置文件就可以將EnCache集成到項目中。EnCache2.x的使用具體步驟如下。
-
創建項目,添加依賴
創建Spring Boot項目,添加spring-boot-starter-cache依賴以及Encache依賴,代碼如下:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> </dependency>
-
添加緩存配置文件
如果Encache的依賴存在,並且在classpath下面有一個名爲encache.xml的Encache的配置文件,那麼EnCacheCacheManager會自動作爲緩存的實現。因此,在resources目錄下創建encache.xml文件作爲Encache緩存的配置文件,代碼如下:
<?xml version="1.0" encoding="UTF-8"?> <ehcache> <diskStore path="java.io.tmpdir/cache"/> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" /> <cache name="book_cache" maxElementsInMemory="10000" eternal="true" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" diskPersistent="true" diskExpiryThreadIntervalSeconds="600" /> </ehcache>
這是一個常規的Encache配置文件,提供了兩個緩存策略,一個是默認的,一個是名爲book_cache。另外,如果你想自定義Encache配置文件的名稱和位置,可以在application.properties中添加如下配置:
spring.cache.ehcache.config=classpath:config/another-config.xml
-
開啓緩存
在項目的入口類上添加@EnableCaching註解開啓緩存,代碼如下:@SpringBootApplication @EnableCaching public class MavenprojectApplication { public static void main(String[] args) { SpringApplication.run(MarvenprojectApplication.class, args); } }
-
創建Book實體類和BookService,代碼如下:
public class BookBean implements Serializable { private Integer id; private String name; private String author; public Integer getId() { return id; } public String getName() { return name; } public String getAuthor() { return author; } public void setId(Integer id) { this.id = id; } public void setName(String name) { this.name = name; } public void setAuthor(String author) { this.author = author; } }
@Repository @CacheConfig(cacheNames = "book_cache") public class BookDao { @Cacheable public BookBean getBookById(Integer id){ System.out.println("getBookById"); BookBean book = new BookBean(); book.setId(id); book.setName("三國演義"); book.setAuthor("羅貫中"); return book; } @CachePut(key = "#book.id") public BookBean updateBookById(BookBean book){ System.out.println("updateBookById"); book.setName("三國演義2"); return book; } @CacheEvict(key = "#id") public void deleteBookById(Integer id){ System.out.println("deleteBookById"); } }
ps:相對的@CacheEvict標註在需要清除緩存元素的方法或類上。 -
創建測試類
創建測試類,對Service中的方法進行測試,代碼如下:
@RunWith(SpringRunner.class) @SpringBootTest public class CacheApplicationTests { @Autowired BookDao bookDao; @Test public void contextLoads(){ bookDao.getBookById(1); bookDao.getBookById(1); bookDao.deleteBookById(1); BookBean b3 = bookDao.getBookById(1); System.out.println("b3:"+b3.getName()); BookBean b = new BookBean(); b.setName("三國演義2"); b.setAuthor("羅貫中"); b.setId(1); bookDao.updateBookById(b); BookBean b4 = bookDao.getBookById(1); System.out.println("b4:"+b4.getName()); } }
ps:使用註解@RunWith(SpringRunner.class),需要首先在pom中引入依賴:
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.2.RELEASE</version> <scope>compile</scope> </dependency>
-
最後執行測試類,得到打印日誌
分析:一開始執行了兩個查詢,但是查詢方法只打印了一次,因爲第二次使用了緩存。接下來執行了刪除方法,刪除方法執行完之後再執行查詢方法,查詢方法又被執行了,因爲在刪除方法中緩存已經被刪除了。再接下來執行了更新方法,更新方法中不僅更新了數據,也更新了緩存,所以在最後的查詢方法中,查詢方法日誌沒打印,說明該方法沒執行,而是使用了緩存中的數據,而緩存中的數據已經被更新了。