spring cache
cache
緩存就是數(shù)據(jù)交換的緩沖區(qū)(稱作Cache),當(dāng)某一硬件要讀取數(shù)據(jù)時(shí),會(huì)首先從緩存中查找需要的數(shù)據(jù),如果找到了則直接執(zhí)行,找不到的話則從內(nèi)存中找。為什么使用緩存?究其原因就是緩存的讀寫(xiě)速度遠(yuǎn)快與磁盤,從減輕I/O開(kāi)銷和加快運(yùn)行速度方便都有很好的效果。那么我們緩存什么?哪些經(jīng)常讀取而又不經(jīng)常修改的數(shù)據(jù),那些數(shù)據(jù)量較大又很少修改的數(shù)據(jù)。
緩存更新策略
- FIFO(First In First Out) 隊(duì)列,先進(jìn)先出
- LFU(Least Frequently Used):最近最少使用算法,一定時(shí)間段內(nèi)使用次數(shù)(頻率)最少的那個(gè)被移除,借助計(jì)數(shù)器實(shí)現(xiàn);
- LRU(Least Recently Used):最久未使用算法,使用時(shí)間距離現(xiàn)在最久的那個(gè)被移除,借助計(jì)數(shù)器和隊(duì)列實(shí)現(xiàn);
- TTL(Time To Live ):存活期,即從緩存中創(chuàng)建時(shí)間點(diǎn)開(kāi)始直到它到期的一個(gè)時(shí)間段(不管在這個(gè)時(shí)間段內(nèi)有沒(méi)有訪問(wèn)都將過(guò)期)
- TTI(Time To Idle):空閑期,即一個(gè)數(shù)據(jù)多久沒(méi)被訪問(wèn)將從緩存中移除的時(shí)間。
搭建cache
- 添加項(xiàng)目maven依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2.啟動(dòng)類開(kāi)啟緩存功能
/**
* 注解 @EnableCaching 開(kāi)啟緩存功能,放在配置類或啟動(dòng)類上
*
* @author hui.wang09
* @since 14 November 2018
*/
@SpringBootApplication
@EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3.使用cache注解添加緩存
/**
* 使用spring cache
*
* 常用注解含義
* 注解@CacheConfig,在類上設(shè)置當(dāng)前緩存的一些公共設(shè)置,比如緩存名稱;
* 注解@Cacheable,作用在方法上,觸發(fā)緩存讀取操作。表明該方法的結(jié)果是可以緩存的,如果緩存存在,則目標(biāo)方法不會(huì)被調(diào)用,直接取出緩存。
* 注解@CacheEvice,作用在方法上,觸發(fā)緩存失效操作,刪除緩存項(xiàng)或者清空緩存;
* 注解@CachePut,作用在方法上,觸發(fā)緩存更新操作
* 注解@Caching,作用在方法上,綜合上面的各種操作,在有些場(chǎng)景上,調(diào)用業(yè)務(wù)會(huì)觸發(fā)多種緩存操作。
*
*
* @author hui.wang09
* @since 14 November 2018
*/
@RestController
public class HelloController {
private static Logger LOGGER = LoggerFactory.getLogger(HelloController.class);
/**
* 注解@Cacheable可以標(biāo)記在一個(gè)方法上,也可以標(biāo)記在一個(gè)類上。當(dāng)標(biāo)記在一個(gè)方法上時(shí)表示該方法是支持緩存的,
* 當(dāng)標(biāo)記在一個(gè)類上時(shí)則表示該類所有的方法都是支持緩存的。@Cacheable可以指定三個(gè)屬性,value、key和condition。
*
* value:緩存的名稱,在 spring 配置文件中定義,必須指定至少一個(gè)。如@Cacheable(value=”mycache”)
* key:緩存的 key,可以為空,如果指定要按照SpEL表達(dá)式編寫(xiě),如果不指定,則缺省按照方法的所有參數(shù)進(jìn)行組合。
* 如@Cacheable(value=”mycache”,key=”#request”)
* condition:緩存的條件,可以為空,使用 SpEL 編寫(xiě),返回 true 或者 false,只有為 true 才進(jìn)行緩存。
* 如@Cacheable(value=”mycache”,condition=”#request.length()>2”)
*
*/
@RequestMapping("/hello")
@Cacheable(value = "myEhCache", key = "#request")
public String hello(@RequestParam String request) {
LOGGER.info("==========================");
LOGGER.info("執(zhí)行hello方法");
LOGGER.info("==========================");
return request;
}
/**
* 注解@CachePut使用方式和@Cacheable是一樣的
* Spring在每次執(zhí)行前都會(huì)檢查Cache中是否存在相同key的緩存元素,如果存在就不再執(zhí)行該方法,
* 而是直接從緩存中獲取結(jié)果進(jìn)行返回,否則才會(huì)執(zhí)行并將返回結(jié)果存入指定的緩存中。
*
*/
@RequestMapping("/put")
@CachePut(value = "mycache", key = "#request")
public String put(@RequestParam String request) {
LOGGER.info("==========================");
LOGGER.info("執(zhí)行put方法");
LOGGER.info("==========================");
return request + 1;
}
}
- 此時(shí)訪問(wèn)hello接口第一次會(huì)執(zhí)行方法,打印日志,并將返回值緩存到緩存中,當(dāng)?shù)诙握{(diào)用hello方法,傳遞相同值的時(shí)候,不會(huì)執(zhí)行方法,會(huì)直接調(diào)用spring cache返回緩存中的值
- 調(diào)用put方法,會(huì)執(zhí)行方法,打印日志,并將相同key的緩存值更新
注解詳解
-
@CacheConfig:在類上設(shè)置當(dāng)前緩存的一些公共設(shè)置,比如緩存名稱; -
@Cacheable:作用在方法上,觸發(fā)緩存讀取操作。表明該方法的結(jié)果是可以緩存的,如果緩存存在,則目標(biāo)方法不會(huì)被調(diào)用,直接取出緩存。@Cacheable可以指定三個(gè)屬性:value、key和condition。
value:緩存的名稱,在 spring 配置文件中定義,必須指定至少一個(gè)。如@Cacheable(value=”mycache”)
key:緩存的 key,可以為空,如果指定要按照SpEL表達(dá)式編寫(xiě),如果不指定,則缺省按照方法的所有參數(shù)進(jìn)行組合。如@Cacheable(value=”mycache”,key=”#request”)
condition:緩存的條件,可以為空,使用 SpEL 編寫(xiě),返回 true 或者 false,只有為 true 才進(jìn)行緩存。如@Cacheable(value=”mycache”,condition=”#request.length()>2”) -
@CacheEvice:作用在方法上,觸發(fā)緩存失效操作,刪除緩存項(xiàng)或者清空緩存; -
@CachePut:作用在方法上,觸發(fā)緩存更新操作 -
@Caching:作用在方法上,綜合上面的各種操作,在有些場(chǎng)景上,調(diào)用業(yè)務(wù)會(huì)觸發(fā)多種緩存操作
整合EhCache
1.添加maven依賴
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
- 在application配置文件配置項(xiàng)目的緩存類型,并指定ehcache配置文件路徑
# 緩存類型(ehcache、redis)
spring.cache.type=ehcache
# ehcache 配置文件
spring.cache.ehcache.config=classpath:ehcache.xml
- 配置ehcache,在classpath路徑下創(chuàng)建ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<!-- 磁盤緩存位置 -->
<diskStore path="java.io.tmpdir/ehcache"/>
<!--
磁盤存儲(chǔ):將緩存中暫時(shí)不使用的對(duì)象,轉(zhuǎn)移到硬盤,類似于Windows系統(tǒng)的虛擬內(nèi)存
path:指定在硬盤上存儲(chǔ)對(duì)象的路徑
path可以配置的目錄有:
user.home(用戶的家目錄)
user.dir(用戶當(dāng)前的工作目錄)
java.io.tmpdir(默認(rèn)的臨時(shí)目錄)
ehcache.disk.store.dir(ehcache的配置目錄)
絕對(duì)路徑(如:d:\\ehcache)
查看路徑方法:String tmpDir = System.getProperty("java.io.tmpdir");
-->
<!-- 默認(rèn)緩存 -->
<defaultCache
maxEntriesLocalHeap="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxEntriesLocalDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</defaultCache>
<!--
name:Cache 的唯一標(biāo)識(shí)
maxElementsInMemory:內(nèi)存中允許存儲(chǔ)的最大的元素個(gè)數(shù)
maxElementsOnDisk:硬盤最大緩存?zhèn)€數(shù),0代表無(wú)限個(gè)
clearOnFlush:內(nèi)存數(shù)量最大時(shí)是否清除
eternal:緩存對(duì)象是否永久有效,如果是,超時(shí)設(shè)置將被忽略
overflowToDisk:內(nèi)存不足(超過(guò) maxElementsInMemory)時(shí),是否啟用磁盤緩存
timeToIdleSeconds:設(shè)置對(duì)象在失效前的允許閑置時(shí)間(單位:秒)。僅當(dāng)eternal=false對(duì)象不是永久有效時(shí)使用,可選屬性,默認(rèn)值是0,也就是可閑置時(shí)間無(wú)窮大
timeToLiveSeconds:緩存數(shù)據(jù)的生存時(shí)間(TTL),也就是一個(gè)元素從構(gòu)建到消亡的最大時(shí)間間隔值,這只能在元素不是永久駐留時(shí)有效,如果該值是0就意味著元素可以停頓無(wú)窮長(zhǎng)的時(shí)間
diskPersistent:是否將緩存數(shù)據(jù)持久化到磁盤上,如果為 true,JVM 重啟數(shù)據(jù)依然存在。默認(rèn)值是false
diskSpoolBufferSizeMB:這個(gè)參數(shù)設(shè)置DiskStore(磁盤緩存)的緩存區(qū)大小。默認(rèn)是30MB。每個(gè)Cache都應(yīng)該有自己的一個(gè)緩沖區(qū)
diskExpiryThreadIntervalSeconds:磁盤失效線程運(yùn)行時(shí)間間隔,默認(rèn)是120秒
memoryStoreEvictionPolicy:當(dāng)達(dá)到 maxElementsInMemory 限制時(shí),Ehcache 將根據(jù)指定策略清除內(nèi)存。默認(rèn)為 LRU(最近最少使用),其他策略有 FIFO(先進(jìn)先出),LFU(較少使用)
-->
<!-- 自定義緩存 -->
<cache name="myEhCache"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="50"
timeToLiveSeconds="50"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
- 使用ehcache
/**
* @author hui.wang09
* @since 14 November 2018
*/
@RestController
@CacheConfig(cacheNames = "myEhCache")
public class EhCacheController {
private static Logger LOGGER = LoggerFactory.getLogger(EhCacheController.class);
@RequestMapping("/ehcache")
@Cacheable(key = "#request")
public String ehcacahe(@RequestParam String request) {
LOGGER.info("==========================");
LOGGER.info("執(zhí)行ehcache方法");
LOGGER.info("==========================");
return request;
}
}
需要注意代碼中@CacheConfig寫(xiě)的cacheNames需要和ehcache配置的cache name一致
github連接