SpringBoot淺析緩存機(jī)制之Ehcache?2.x應(yīng)用
介紹
Spring 3.1 中開始對緩存提供支持,核心思路是對方法的緩存,當(dāng)開發(fā)者調(diào)用一個方法時,將方法的參數(shù)和返回值作為 key/value 緩存起來,當(dāng)再次調(diào)用改方法時,如果緩存中有數(shù)據(jù),就直接從緩存中獲取,否則再去執(zhí)行該方法。但是,Spring 中并未提供緩存的實現(xiàn),而是提供了一套緩存 API ,開發(fā)者可以自由選擇緩存的實現(xiàn),目前 Spring Boot 支持的緩存有如下幾種:
- JCache(JSR-107)
- EhCache 2.x
- Hazelcast
- Infinispan
- Couchbase
- Redis
- Caffeine
- Simple
此處只介紹常用的緩存實現(xiàn) Ehcache 2.x 和 Redis,由于 Spring 早已將緩存領(lǐng)域統(tǒng)一,因此無論使用哪種緩存實現(xiàn),不同的只是緩存配置,開發(fā)者使用的緩存注解是一致的(Spring 緩存注解和各種緩存實現(xiàn)的關(guān)系就像 JDBC 和各種數(shù)據(jù)庫驅(qū)動的關(guān)系一樣)。
Ehcache 2.x 緩存
Ehcache 緩存在Java開發(fā)領(lǐng)域久負(fù)盛名,在Spring Boot 中,只需要一個配置文件就可以將 Ehcache 集成到項目中。步驟如下:
1. 創(chuàng)建項目添加緩存依賴
創(chuàng)建 Spring Boot 項目,添加 spring-boot-starter-cache 依賴以及 Ehcache 依賴
<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>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
2. 添加緩存配置文件
如果 Ehcache 的依賴存在,并且在 classpath 下有一個名為 echache.xml 的 Ehcache 配置文件,那么 EhCacheCacheManager 將會自動作為緩存的實現(xiàn)。因此,在 resources 目錄下創(chuàng)建 ehcache.xml 文件作為 Ehcache 緩存的配置文件,如下:
<ehcache>
<diskStore path="java.io.tmpdir/cache"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
/>
<!--
name:緩存名稱
maxElementsInMemory:緩存最大個數(shù)
eternal:緩存對象是否永久有效。一旦設(shè)置了永久有效,timeout將不起作用
timeToIdleSeconds:緩存對象在失效前允許閑置時間(秒),當(dāng)eternal為false時生效
timeToLiveSeconds:緩存對象在失效前允許存活的時間(秒),當(dāng)eternal為false時生效
overflowToDisk:當(dāng)內(nèi)存中的對象數(shù)量達(dá)到maxElementsInMemory時, Ehcache 是否將對象寫到磁盤中
diskExpiryThreadIntervalSeconds:磁盤失效線程運(yùn)行時間間隔
-->
<cache name="book_cache"
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="600"/>
</ehcache>
這是一個常規(guī)的 Ehcache 配置文件,提供了兩個緩存策略,一個是默認(rèn)的,另一個名為 book_cache 。還有更為詳細(xì)的 Ehcache 配置,此處不再一一介紹。如果開發(fā)者想自定義 Ehcache 配置文件的名稱和位置,可以在 application.properties 中添加如下配置:
spring.cache.ehcache.config=classpath:ehcache2.xml
3. 開啟緩存
在項目的入口類添加 @EnableCaching 注解開啟緩存,如下
@SpringBootApplication
@EnableCaching
public class CacheApplication {
public static void main(String[] args) {
SpringApplication.run(CacheApplication.class, args);
}
}
4. 創(chuàng)建 BookDao
Book
public class Book implements Serializable {
private Integer id;
private String name;
private String author;
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", author='" + author + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}BookDao
@Repository
@CacheConfig(cacheNames = "book_cache")
public class BookDao {
@Cacheable
public Book getBookById(Integer id) {
System.out.println("getBookById");
Book book = new Book();
book.setId(id);
book.setName("三國演義");
book.setAuthor("羅貫中");
return book;
}
@CachePut(key = "#book.id")
public Book updateBookById(Book book) {
System.out.println("updateBookById");
book.setName("三國演義2");
return book;
}
@CacheEvict(key = "#id")
public void deleteBookById(Integer id) {
System.out.println("deleteBookById");
}
}
代碼解釋:
在 BookDao 上添加 @CacheConfig 注解指明使用的緩存名字,這個配置可選,若不使用 @CacheConfig ,則直接在 @Cacheable 注解中指明緩存名字
在 getBookById 方法上添加 @Cacheable 注解表示對該方法進(jìn)行緩存,默認(rèn)情況下,緩存的key是方法的參數(shù),緩存的 value 是方法的返回值。當(dāng)開發(fā)者在其他類中調(diào)用該方法時,首先會根據(jù)調(diào)用參數(shù)查看緩存中是否有相關(guān)數(shù)據(jù),若有,則直接使用緩存數(shù)據(jù),該方法不會執(zhí)行,否則執(zhí)行該方法,執(zhí)行成功后將返回值緩存起來,但若是在當(dāng)前類中調(diào)用該方法,則緩存不會生效
@Cacheable 注解中還有一個屬性 condition 用來描述緩存的執(zhí)行時機(jī),例如 @Cacheable(“#id%2==0”) 表示 id 對 2 取模為0時才進(jìn)緩存,否則不緩存
如果開發(fā)者不想使用默認(rèn)到的 key ,也可以像 updateBookById 和 deleteBookById 一樣自定義 key,@CachePut(key = “#book.id”) 表示緩存的key 為參數(shù)book 對象中 id 的值,@CacheEvict(key = “#id”)表示緩存的key為參數(shù)id。除了這種使用參數(shù)定義 key 的方式外,Spring 還提供了一個 root 對象用來生成 key ,如圖
| 屬性名稱 | 屬性描述 | 用法示例 |
| — | — | — |
| methodName | 當(dāng)前方法名 | #root.methodName |
| method | 當(dāng)前方法對象 | #root.method.name |
| caches | 當(dāng)前方法使用的緩存 | #root.caches[0].name |
| target | 當(dāng)前被調(diào)用的對象 | #root.target |
| targetClass | 當(dāng)前被調(diào)用的對象的class | #root.targetClass |
| args | 當(dāng)前方法參數(shù)數(shù)組 | #root.args[0] |
如果這些 key 不能滿足開發(fā)需求,開發(fā)者也可以自定義緩存 key 的生成器 KeyGenerator,如下
@Component
public class MyKeyGenerator implements KeyGenerator {
@Override
public Object generate(Object target, Method method, Object... params) {
return Arrays.toString(params);
}
}
然后在 @Cacheable 注解中引用 MyKeyGenerator 實例即可
@Service
@CacheConfig(cacheNames = "book_cache")
public class BookDao {
@Autowired
MyKeyGenerator myKeyGenerator;
@Cacheable(keyGenerator = "myKeyGenerator")
public Book getBookById(Integer id) {
System.out.println("getBookById");
Book book = new Book();
book.setId(id);
book.setName("三國演義");
book.setAuthor("羅貫中");
return book;
}
@CachePut(key = "#book.id")
public Book updateBookById(Book book) {
System.out.println("updateBookById");
book.setName("三國演義2");
return book;
}
@CacheEvict(key = "#id")
public void deleteBookById(Integer id) {
System.out.println("deleteBookById");
}
}
MyKeyGenerator 中的 generate 方法的參數(shù)分別是當(dāng)前對象、當(dāng)前請求的方法以及方法的參數(shù),開發(fā)者可根據(jù)這些信息組成一個新的 key 返回,返回值就是緩存的 key。
- @CachePut 注解一般用于數(shù)據(jù)更新方法上,與 @Cacheable 注解不同,添加了 @CachePut 注解的方法每次在執(zhí)行時都不去檢查緩存中是否有數(shù)據(jù),而是直接執(zhí)行方法,然后將方法的執(zhí)行結(jié)果緩存起來,如果 key 對應(yīng)的數(shù)據(jù)已經(jīng)被緩存起來了,就會覆蓋之前的數(shù)據(jù),這樣可以避免再次加載數(shù)據(jù)時獲取到臟數(shù)據(jù)。同時 @CachePut 具有和 @Cacheable 類似的屬性
- @CacheEvict 注解一般用于刪除方法上,表示移除一個 key 對應(yīng)的緩存。@CacheEvict 注解由兩個特殊屬性:allEntries 和 beforeInvocation,其中 allEntries 表示是否將所有的緩存數(shù)據(jù)都移除,默認(rèn)為 false,beforeInvocation 表示是否在方法執(zhí)行之前移除緩存中的數(shù)據(jù),默認(rèn)為 false ,即在方法執(zhí)行之后移除緩存中的數(shù)據(jù) 5. 創(chuàng)建測試類
5 .創(chuàng)建測試類
對 Service 中的方法進(jìn)行測試
@RunWith(SpringRunner.class)
@SpringBootTest
public class CacheApplicationTests {
@Autowired
BookDao bookDao;
@Test
public void contextLoads() {
bookDao.deleteBookById(1);
bookDao.getBookById(1);
bookDao.getBookById(1);
bookDao.deleteBookById(1);
Book b3 = bookDao.getBookById(1);
System.out.println("b3:"+b3);
Book b = new Book();
b.setName("三國演義");
b.setAuthor("羅貫中");
b.setId(1);
bookDao.updateBookById(b);
Book b4 = bookDao.getBookById(1);
System.out.println("b4:"+b4);
}
}
執(zhí)行該方法,控制臺打印日志如下:
deleteBookById
getBookById
deleteBookById
getBookById
b3:Book{id=1, name='三國演義', author='羅貫中'}
updateBookById
b4:Book{id=1, name='三國演義2', author='羅貫中'}
為了防止來回測試緩存的影響,這里先執(zhí)行刪除操作(同時也會刪除緩存)。然后執(zhí)行了一次查詢,正常打印,接著又執(zhí)行了一次查詢沒打?。ㄖ苯幼x取的緩存),然后執(zhí)行刪除,接著再執(zhí)行查詢正常打印(刪除操作也刪除了緩存),再接著執(zhí)行更新操作(同時更新了緩存),最后再次查詢,打印更新后的數(shù)據(jù)。
到此這篇關(guān)于SpringBoot淺析緩存機(jī)制之Ehcache 2.x應(yīng)用的文章就介紹到這了,更多相關(guān)SpringBoot Ehcache 2.x內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中StringRedisTemplate和RedisTemplate的區(qū)別及使用方法
本文主要介紹了Java中StringRedisTemplate和RedisTemplate的區(qū)別及使用方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
Java實現(xiàn)經(jīng)典游戲飛機(jī)大戰(zhàn)-I的示例代碼
《飛機(jī)大戰(zhàn)-I》是一款融合了街機(jī)、競技等多種元素的經(jīng)典射擊手游。本文將利用java語言實現(xiàn)這游戲,文中采用了swing技術(shù)進(jìn)行了界面化處理,感興趣的可以了解一下2022-02-02
Mybatis注解實現(xiàn)多數(shù)據(jù)源讀寫分離詳解
這篇文章主要給大家介紹了關(guān)于Mybatis注解實現(xiàn)多數(shù)據(jù)源讀寫分離的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Mybatis具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
強(qiáng)烈推薦 5 款好用的REST API工具(收藏)
市面上可用的 REST API 工具選項有很多,我們來看看其中一些開發(fā)人員最喜歡的工具。本文通過圖文實例代碼相結(jié)合給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2020-12-12
Java正則驗證電話,手機(jī),郵箱,日期,金額的方法示例
這篇文章主要介紹了Java正則驗證電話,手機(jī),郵箱,日期,金額的方法,結(jié)合具體實例形式分析了Java針對電話,手機(jī),郵箱,日期,金額的正則判定操作技巧,需要的朋友可以參考下2017-03-03

