SpringBoot系列(7)---SpringBoot-Cache(EhCache)

SpringBoot提供數據緩存的功能,相信非常多人已經用過cache了。因爲數據庫的IO瓶頸應該大家也吃過不少虧了,所以一般情況下我們都會引入非常多的緩存策略,例如引入redis,引入hibernate的二級緩存等等。

SpringBoot在annotation的層面給我們實現了cache,當然這也是得益於Spring的AOP。所有的緩存配置只是在annotation層面配置,完全沒有侵入到我們的代碼當中,就像我們的聲明式事務一樣。

Spring定義了CacheManager和Cache接口統一不同的緩存技術。其中CacheManager是Spring提供的各種緩存技術的抽象接口。而Cache接口包含緩存的各種操作,當然我們一般情況下不會直接操作Cache接口。


Spring針對不同的緩存技術,需要實現不同的cacheManager,Spring定義瞭如下的cacheManger實現

CacheManger 描述
SimpleCacheManager 使用簡單的Collection來存儲緩存,主要用於測試
ConcurrentMapCacheManager 使用ConcurrentMap作爲緩存技術(默認)
NoOpCacheManager 測試用
EhCacheCacheManager 使用EhCache作爲緩存技術,以前在hibernate的時候經常用
GuavaCacheManager 使用google guava的GuavaCache作爲緩存技術
HazelcastCacheManager 使用Hazelcast作爲緩存技術
JCacheCacheManager 使用JCache標準的實現作爲緩存技術,如Apache Commons JCS
RedisCacheManager 使用Redis作爲緩存技術

當然常規的SpringBoot已經爲我們自動配置了EhCache、Collection、Guava、ConcurrentMap等緩存,默認使用SimpleCacheConfiguration,即使用ConcurrentMapCacheManager。SpringBoot的application.properties配置文件,使用spring.cache前綴的屬性進行配置。

spring.cache.type=#緩存的技術類型
spring.cache.cache-names=應用程序啓動創建緩存的名稱
spring.cache.ehcache.config=ehcache的配置文件位置
spring.cache.infinispan.config=infinispan的配置文件位置
spring.cache.jcache.config=jcache配置文件位置
spring.cache.jcache.provider=當多個jcache實現類時,指定選擇jcache的實現類

在SpringBoot環境下我們需要導入相關緩存技術的依賴,並在配置類當中配置@EnableCaching開啓緩存技術。

我們這裏不適用默認的ConcurrentMapCache 而是使用 EhCache

所以我在resources目錄下創建了ehcache.xml的配置文件,然後在application.properties 設置type爲ehcache(intellij有明確的提示):

ehcache.xml:

<ehcache>
    <!-- 指定一個文件目錄,當EHCache把數據寫到硬盤上時,將把數據寫到這個文件目錄下 -->
    <diskStore path="java.io.tmpdir"/>

    <!-- 設定緩存的默認數據過期策略 -->
    
    <cache name="weibo" maxElementsInMemory="10000" />
 
    
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="10"
            timeToLiveSeconds="120"
            diskPersistent="false"
            memoryStoreEvictionPolicy="LRU"
            diskExpiryThreadIntervalSeconds="120"/>

    <!-- maxElementsInMemory 內存中最大緩存對象數,看着自己的heap大小來搞 -->
    <!-- eternal:true表示對象永不過期,此時會忽略timeToIdleSeconds和timeToLiveSeconds屬性,默認爲false -->
    <!-- maxElementsOnDisk:硬盤中最大緩存對象數,若是0表示無窮大 -->
    <!-- overflowToDisk:true表示當內存緩存的對象數目達到了maxElementsInMemory界限後,
    會把溢出的對象寫到硬盤緩存中。注意:如果緩存的對象要寫入到硬盤中的話,則該對象必須實現了Serializable接口才行。-->
    <!-- diskSpoolBufferSizeMB:磁盤緩存區大小,默認爲30MB。每個Cache都應該有自己的一個緩存區。-->
    <!-- diskPersistent:是否緩存虛擬機重啓期數據  -->
    <!-- diskExpiryThreadIntervalSeconds:磁盤失效線程運行時間間隔,默認爲120秒 -->

    <!-- timeToIdleSeconds: 設定允許對象處於空閒狀態的最長時間,以秒爲單位。當對象自從最近一次被訪問後,
    如果處於空閒狀態的時間超過了timeToIdleSeconds屬性值,這個對象就會過期,
    EHCache將把它從緩存中清空。只有當eternal屬性爲false,該屬性纔有效。如果該屬性值爲0,
    則表示對象可以無限期地處於空閒狀態 -->

    <!-- timeToLiveSeconds:設定對象允許存在於緩存中的最長時間,以秒爲單位。當對象自從被存放到緩存中後,
    如果處於緩存中的時間超過了 timeToLiveSeconds屬性值,這個對象就會過期,
    EHCache將把它從緩存中清除。只有當eternal屬性爲false,該屬性纔有效。如果該屬性值爲0,
    則表示對象可以無限期地存在於緩存中。timeToLiveSeconds必須大於timeToIdleSeconds屬性,纔有意義 -->

    <!-- memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,
    Ehcache將會根據指定的策略去清理內存。可選策略有:LRU(最近最少使用,默認策略)、
    FIFO(先進先出)、LFU(最少訪問次數)。-->

</ehcache>

application.properties:

spring.cache.type=ehcache
spring.cache.ehcache.config=ehcache.xml
在配置類配置@EnableCaching

@SpringBootApplication
@EnableCaching
public class DemoApplication extends WebMvcConfigurerAdapter {

然後說說4個annotation的配置:

@Cacheable  在方法執行前Spring先是否有緩存數據,如果有直接返回。如果沒有數據,調用方法並將方法返回值存放在緩存當中。

@CachePut   無論怎樣,都將方法的範湖值放到緩存當中。

@CacheEvict   將一條或者多條數據從緩存中刪除。

@Caching  可以通過@Caching註解組合多個註解集合在一個方法上


使用演示JPA時候的方法進行緩存測試:

@Transactional
@CachePut(value = "weibo",key="#weibo.weiboId")
public Weibo saveWeibo(Weibo weibo){
    this.weiboRepository.save(weibo);
    return weibo;
}

@Cacheable(value = "weibo")
public Weibo getWeiboById(long id){
    return this.weiboRepository.getByWeiboId(id);
}


@Transactional
@CacheEvict(value = "weibo",key = "#weibo.weiboId")
public void remove(Weibo weibo){
    this.weiboRepository.delete(weibo);
}


當然如果我們想單獨配置一下weibo這個緩存可以通過ehcache.xml進行單獨配置,不過需要提醒的是 maxElementsInMemory屬性配置是必須的,否則無法啓動SpringBoot應用。

<cache name="weibo" maxElementsInMemory="10000" overflowToDisk="false" timeToIdleSeconds="60"  timeToLiveSeconds="120" />

通過Controller進行測試,緩存生效:

@RestController
@RequestMapping("/cache")
public class CacheTestController {

    @Autowired
    private WeiboService weiboService;
    @Autowired
    private UserRepository userRepository;

    @RequestMapping("/getWeibo/{id}")
    public Weibo getWeibo(@PathVariable("id") long id){
        return weiboService.getWeiboById(id);
    }

    @RequestMapping("/addWeibo")
    public Weibo addWeibo(String username,String weiboText){
        User user = userRepository.getByUsernameIs(username);
        Weibo weibo = new Weibo(user,weiboText,new Date(System.currentTimeMillis()));
        return this.weiboService.saveWeibo(weibo);
    }

    @RequestMapping("/delete/{id}")
    public Weibo delete(@PathVariable("id") long id){
        Weibo weibo = this.weiboService.getWeiboById(id);
        this.weiboService.remove(weibo);
        return weibo;
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章