地址:https://www.cnblogs.com/yueshutong/p/9381540.html
一:Spring緩存抽象
Spring從3.1開始定義了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口來統(tǒng)一不同的緩存技術(shù)遇革;并支持使用JCache(JSR-107)注解簡化我們開發(fā)琢唾;
Cache接口為緩存的組件規(guī)范定義憔四,包含緩存的各種操作集合;
Cache接口下Spring提供了各種xxxCache的實現(xiàn)掂为;如RedisCache甩十,EhCacheCache ,ConcurrentMapCache等闹炉;
每次調(diào)用需要緩存功能的方法時懈糯,Spring會檢查檢查指定參數(shù)的指定的目標方法是否已經(jīng)被調(diào)用過;如果有就直接從緩存中獲取方法調(diào)用后的結(jié)果颁督,如果沒有就調(diào)用方法并緩存結(jié)果后返回給用戶践啄。下次調(diào)用直接從緩存中獲取。
使用Spring緩存抽象時我們需要關(guān)注以下兩點沉御;
1屿讽、確定方法需要被緩存以及他們的緩存策略
2、從緩存中讀取之前緩存存儲的數(shù)據(jù)
二:幾個重要概念&緩存注解
名稱解釋
Cache緩存接口吠裆,定義緩存操作伐谈。實現(xiàn)有:RedisCache烂完、EhCacheCache、ConcurrentMapCache等
CacheManager緩存管理器衩婚,管理各種緩存(cache)組件
@Cacheable主要針對方法配置窜护,能夠根據(jù)方法的請求參數(shù)對其進行緩存
@CacheEvict清空緩存
@CachePut保證方法被調(diào)用效斑,又希望結(jié)果被緩存非春。
與@Cacheable區(qū)別在于是否每次都調(diào)用方法,常用于更新
@EnableCaching開啟基于注解的緩存
keyGenerator緩存數(shù)據(jù)時key生成策略
serialize緩存數(shù)據(jù)時value序列化策略
@CacheConfig統(tǒng)一配置本類的緩存注解的屬性
@Cacheable/@CachePut/@CacheEvict 主要的參數(shù)
名稱解釋
value緩存的名稱缓屠,在 spring 配置文件中定義奇昙,必須指定至少一個
例如:
@Cacheable(value=”mycache”) 或者
@Cacheable(value={”cache1”,”cache2”}
key緩存的 key,可以為空敌完,如果指定要按照 SpEL 表達式編寫储耐,
如果不指定,則缺省按照方法的所有參數(shù)進行組合
例如:
@Cacheable(value=”testcache”,key=”#id”)
condition緩存的條件滨溉,可以為空什湘,使用 SpEL 編寫,返回 true 或者 false晦攒,
只有為 true 才進行緩存/清除緩存
例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
unless否定緩存闽撤。當條件結(jié)果為TRUE時,就不會緩存脯颜。
@Cacheable(value=”testcache”,unless=”#userName.length()>2”)
allEntries
(@CacheEvict )
是否清空所有緩存內(nèi)容哟旗,缺省為 false,如果指定為 true栋操,
則方法調(diào)用后將立即清空所有緩存
例如:
@CachEvict(value=”testcache”,allEntries=true)
beforeInvocation
(@CacheEvict)
是否在方法執(zhí)行前就清空闸餐,缺省為 false,如果指定為 true矾芙,
則在方法還沒有執(zhí)行的時候就清空緩存舍沙,缺省情況下,如果方法
執(zhí)行拋出異常剔宪,則不會清空緩存
例如:
@CachEvict(value=”testcache”场勤,beforeInvocation=true)
三:SpEL上下文數(shù)據(jù)
Spring Cache提供了一些供我們使用的SpEL上下文數(shù)據(jù),下表直接摘自Spring官方文檔:
名稱位置描述示例
methodNameroot對象當前被調(diào)用的方法名#root.methodname
methodroot對象當前被調(diào)用的方法#root.method.name
targetroot對象當前被調(diào)用的目標對象實例#root.target
targetClassroot對象當前被調(diào)用的目標對象的類#root.targetClass
argsroot對象當前被調(diào)用的方法的參數(shù)列表#root.args[0]
cachesroot對象當前方法調(diào)用使用的緩存列表#root.caches[0].name
Argument Name執(zhí)行上下文當前被調(diào)用的方法的參數(shù)歼跟,如findArtisan(Artisan artisan),可以通過#artsian.id獲得參數(shù)#artsian.id
result執(zhí)行上下文方法執(zhí)行后的返回值(僅當方法執(zhí)行后的判斷有效和媳,如 unless cacheEvict的beforeInvocation=false)#result
注意:
1.當我們要使用root對象的屬性作為key時我們也可以將“#root”省略,因為Spring默認使用的就是root對象的屬性哈街。 如
@Cacheable(key = "targetClass + methodName +#p0")
2.使用方法參數(shù)時我們可以直接使用“#參數(shù)名”或者“#p參數(shù)index”留瞳。 如:
@Cacheable(value="users", key="#id")
@Cacheable(value="users", key="#p0")
SpEL提供了多種運算符
類型運算符
關(guān)系<,>骚秦,<=她倘,>=璧微,==,!=硬梁,lt前硫,gt,le荧止,ge屹电,eq,ne
算術(shù)+跃巡,- 危号,* ,/素邪,%外莲,^
邏輯&&,||兔朦,!偷线,and,or沽甥,not声邦,between,instanceof
條件?: (ternary)安接,?: (elvis)
正則表達式matches
其他類型?.翔忽,?[…],![…]盏檐,^[…]歇式,$[…]
以上的知識點適合你遺忘的時候來查閱,下面正式進入學習胡野!
四:開始使用
環(huán)境:Spring boot 2.0.3
IDE:IDEA
1.開始使用前需要導入依賴
<dependency>
? ? <groupId>org.springframework.boot</groupId>
? ? <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2.然后在啟動類注解@EnableCaching開啟緩存
@SpringBootApplication
@EnableCaching//開啟緩存
publicclass DemoApplication{
public static void main(String[] args){? ? ? ??
SpringApplication.run(DemoApplication.class, args);? ??
}
}
3.緩存@Cacheable
@Cacheable注解會先查詢是否已經(jīng)有緩存材失,有會使用緩存,沒有則會執(zhí)行方法并緩存硫豆。
@Cacheable(value="emp",key ="targetClass + methodName +#p0")
public List<NewJob> queryAll(User uid){
return newJobDao.findAllByUid(uid);? ??
}
此處的value是必需的龙巨,它指定了你的緩存存放在哪塊命名空間。
此處的key是使用的spEL表達式熊响,參考上章旨别。這里有一個小坑,如果你把methodName換成method運行會報錯汗茄,觀察它們的返回類型秸弛,原因在于methodName是String而methoh是Method。
此處的User實體類一定要實現(xiàn)序列化public class User implements Serializable,否則會報java.io.NotSerializableException異常递览。
到這里叼屠,你已經(jīng)可以運行程序檢驗緩存功能是否實現(xiàn)。
深入源碼绞铃,查看它的其它屬性
我們打開@Cacheable注解的源碼镜雨,可以看到該注解提供的其他屬性,如:
String[]cacheNames()default{};//和value注解差不多儿捧,二選一
StringkeyGenerator()default"";//key的生成器荚坞。key/keyGenerator二選一使用
StringcacheManager()default"";//指定緩存管理器
StringcacheResolver()default"";//或者指定獲取解析器
Stringcondition()default"";//條件符合則緩存
Stringunless()default"";//條件符合則不緩存
booleansync()default false;//是否使用異步模式
4.配置@CacheConfig
當我們需要緩存的地方越來越多,你可以使用@CacheConfig(cacheNames = {"myCache"})注解來統(tǒng)一指定value的值纯命,這時可省略value西剥,如果你在你的方法依舊寫上了value痹栖,那么依然以方法的value值為準亿汞。
使用方法如下:
@CacheConfig(cacheNames = {"myCache"})publicclass BotRelationServiceImpl implements BotRelationService {
@Override
@Cacheable(key ="targetClass + methodName +#p0")//此處沒寫
valuepublic List<BotRelation> findAllLimit(int num){
returnbotRelationRepository.findAllLimit(num);? ??
}? ??
.....}
查看它的其它屬性
StringkeyGenerator()default"";//key的生成器。key/keyGenerator二選一使用
StringcacheManager()default"";//指定緩存管理器
StringcacheResolver()default"";//或者指定獲取解析器
5.更新@CachePut
@CachePut注解的作用 主要針對方法配置揪阿,能夠根據(jù)方法的請求參數(shù)對其結(jié)果進行緩存疗我,和?@Cacheable?不同的是,它每次都會觸發(fā)真實方法的調(diào)用 南捂。簡單來說就是用戶更新緩存數(shù)據(jù)吴裤。但需要注意的是該注解的value?和?key?必須與要更新的緩存相同,也就是與@Cacheable?相同溺健。示例:
@CachePut(value="emp", key ="targetClass + #p0")
public NewJob updata(NewJob job){? ? ? ??
NewJob newJob = newJobDao.findAllById(job.getId());? ? ? ??
newJob.updata(job);returnjob;? ?
?}? ??
@Cacheable(value="emp", key ="targetClass +#p0")//清空緩存
public NewJob save(NewJob job){? ? ? ??
newJobDao.save(job);returnjob;? ??
}
查看它的其它屬性
String[]cacheNames()default{};//與value二選一
StringkeyGenerator()default"";//key的生成器麦牺。key/keyGenerator二選一使用
StringcacheManager()default"";//指定緩存管理器
StringcacheResolver()default"";//或者指定獲取解析器
Stringcondition()default"";//條件符合則緩存
Stringunless()default"";//條件符合則不緩存
6.清除@CacheEvict
@CachEvict?的作用 主要針對方法配置,能夠根據(jù)一定的條件對緩存進行清空 鞭缭。
屬性解釋示例
allEntries是否清空所有緩存內(nèi)容剖膳,缺省為 false,如果指定為 true岭辣,則方法調(diào)用后將立即清空所有緩存@CachEvict(value=”testcache”,allEntries=true)
beforeInvocation是否在方法執(zhí)行前就清空吱晒,缺省為 false,如果指定為 true沦童,則在方法還沒有執(zhí)行的時候就清空緩存仑濒,缺省情況下,如果方法執(zhí)行拋出異常偷遗,則不會清空緩存@CachEvict(value=”testcache”墩瞳,beforeInvocation=true)
示例:
@Cacheable(value="emp",key ="#p0.id")
public NewJob save(NewJob job){? ? ? ?
?newJobDao.save(job);returnjob;? ??
}//清除一條緩存,key為要清空的數(shù)據(jù)@CacheEvict(value="emp",key="#id")
public void delect(int id){? ? ? ??
newJobDao.deleteAllById(id);? ??
}//方法調(diào)用后清空所有緩存
@CacheEvict(value="accountCache",allEntries=true)
public void delectAll(){? ? ? ??
newJobDao.deleteAll();? ??
}//方法調(diào)用前清空所有緩存
@CacheEvict(value="accountCache",beforeInvocation=true)
public void delectAll(){? ? ? ??
newJobDao.deleteAll();? ??
}
其他屬性
String[]cacheNames()default{};//與value二選一
StringkeyGenerator()default"";//key的生成器氏豌。key/keyGenerator二選一使用
StringcacheManager()default"";//指定緩存管理器
StringcacheResolver()default"";//或者指定獲取解析器
Stringcondition()default"";//條件符合則清空
7.組合@Caching
有時候我們可能組合多個Cache注解使用喉酌,此時就需要@Caching組合多個注解標簽了。
@Caching(cacheable = {? ? ? ? ? ?
@Cacheable(value ="emp",key ="#p0"),...
},? ?
?put = {? ? ? ? ? ??
@CachePut(value ="emp",key ="#p0"),...
},
evict = {? ? ? ? ? ??
@CacheEvict(value ="emp",key ="#p0"),? ? ? ? ? ? ....? ??
})? ??
public User save(User user) {? ? ? ? ....? ? }
下面講到的整合第三方緩存組件都是基于上面的已經(jīng)完成的步驟,所以一個應(yīng)用要先做好你的緩存邏輯瞭吃,再來整合其他cache組件碌嘀。
五:整合EHCACHE
Ehcache是一種廣泛使用的開源Java分布式緩存。主要面向通用緩存,Java EE和輕量級容器歪架。它具有內(nèi)存和磁盤存儲股冗,緩存加載器,緩存擴展,緩存異常處理程序,一個gzip緩存servlet過濾器,支持REST和SOAP api等特點。
1.導入依賴
整合ehcache必須要導入它的依賴和蚪。
<dependency>
? ? <groupId>net.sf.ehcache</groupId>
? ? <artifactId>ehcache</artifactId>
</dependency>
<dependency>
? ? <groupId>org.springframework.boot</groupId>
? ? <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2.yml配置
需要說明的是config: classpath:/ehcache.xml可以不用寫止状,因為默認就是這個路徑。但ehcache.xml必須有攒霹。
spring:cache:type: ehcacheehcache:config:classpath:/ehcache.xml
3.ehcache.xml
在resources目錄下新建ehcache.xml怯疤,注釋啥的應(yīng)該可以說相當詳細了
<ehcache>
<!--
? ? ? ? 磁盤存儲:將緩存中暫時不使用的對象,轉(zhuǎn)移到硬盤,類似于Windows系統(tǒng)的虛擬內(nèi)存
? ? ? ? path:指定在硬盤上存儲對象的路徑
? ? ? ? path可以配置的目錄有:
? ? ? ? ? ? user.home(用戶的家目錄)
? ? ? ? ? ? user.dir(用戶當前的工作目錄)
? ? ? ? ? ? java.io.tmpdir(默認的臨時目錄)
? ? ? ? ? ? ehcache.disk.store.dir(ehcache的配置目錄)
? ? ? ? ? ? 絕對路徑(如:d:\\ehcache)
? ? ? ? 查看路徑方法:String tmpDir = System.getProperty("java.io.tmpdir");
? ? -->
<diskStore path="java.io.tmpdir" />
<!--
? ? ? ? defaultCache:默認的緩存配置信息,如果不加特殊說明,則所有對象按照此配置項處理
? ? ? ? maxElementsInMemory:設(shè)置了緩存的上限,最多存儲多少個記錄對象
? ? ? ? eternal:代表對象是否永不過期 (指定true則下面兩項配置需為0無限期)
? ? ? ? timeToIdleSeconds:最大的發(fā)呆時間 /秒
? ? ? ? timeToLiveSeconds:最大的存活時間 /秒
? ? ? ? overflowToDisk:是否允許對象被寫入到磁盤
? ? ? ? 說明:下列配置自緩存建立起600秒(10分鐘)有效 。
? ? ? ? 在有效的600秒(10分鐘)內(nèi)催束,如果連續(xù)120秒(2分鐘)未訪問緩存集峦,則緩存失效。
? ? ? ? 就算有訪問抠刺,也只會存活600秒塔淤。
? ? -->
<defaultCache maxElementsInMemory="10000" eternal="false"? ? ? ? ? ? ? ? ? timeToIdleSeconds="600" timeToLiveSeconds="600" overflowToDisk="true" />
<cache name="myCache" maxElementsInMemory="10000" eternal="false"? ? ? ? ? ? ? ? ? timeToIdleSeconds="120" timeToLiveSeconds="600" overflowToDisk="true" /></ehcache>
4.使用緩存
@CacheConfig(cacheNames = {“myCache”})設(shè)置ehcache的名稱,這個名稱必須在ehcache.xml已配置 速妖。
@CacheConfig(cacheNames = {"myCache"})
publicclass BotRelationServiceImpl implements BotRelationService {
@Cacheable(key ="targetClass + methodName +#p0")
public List<BotRelation> findAllLimit(int num)
{
returnbotRelationRepository.findAllLimit(num);? ??
}
}
整合完畢高蜂!
別忘了在啟動類開啟緩存!
六:整合Redis
Redis 優(yōu)勢
性能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s 罕容。
豐富的數(shù)據(jù)類型 – Redis支持二進制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 數(shù)據(jù)類型操作备恤。
原子 – Redis的所有操作都是原子性的,意思就是要么成功執(zhí)行要么失敗完全不執(zhí)行锦秒。單個操作是原子性的露泊。多個操作也支持事務(wù),即原子性脂崔,通過MULTI和EXEC指令包起來滤淳。
豐富的特性 – Redis還支持 publish/subscribe, 通知, key 過期等等特性
1.啟動Redis
下載地址:https://github.com/MicrosoftArchive/redis/releases?
2.導入依賴
就只需要這一個依賴!不需要spring-boot-starter-cache
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
當你導入這一個依賴時砌左,SpringBoot的CacheManager就會使用RedisCache脖咐。
如果你的Redis使用默認配置,這時候已經(jīng)可以啟動程序了汇歹。
3.配置Redis
# Redis數(shù)據(jù)庫索引(默認為0)
spring.redis.database=1
# Redis服務(wù)器地址
spring.redis.host=127.0.0.1
# Redis服務(wù)器連接端口
spring.redis.port=6379
# Redis服務(wù)器連接密碼(默認為空)
spring.redis.password=
# 連接池最大連接數(shù)(使用負值表示沒有限制)
spring.redis.pool.max-active=1000
# 連接池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.pool.max-wait=-1
# 連接池中的最大空閑連接
spring.redis.pool.max-idle=10
# 連接池中的最小空閑連接
spring.redis.pool.min-idle=2
# 連接超時時間(毫秒)
spring.redis.timeout=0
4.模板編程
除了使用注解屁擅,我們還可以使用Redis模板。?
Spring boot集成 Redis 客戶端jedis产弹。封裝Redis 連接池派歌,以及操作模板弯囊。
@AutowiredprivateStringRedisTemplate stringRedisTemplate;//操作key-value都是字符串@AutowiredprivateRedisTemplate redisTemplate;//操作key-value都是對象/**
? ? *? Redis常見的五大數(shù)據(jù)類型:
? ? *? stringRedisTemplate.opsForValue();[String(字符串)]
? ? *? stringRedisTemplate.opsForList();[List(列表)]
? ? *? stringRedisTemplate.opsForSet();[Set(集合)]
? ? *? stringRedisTemplate.opsForHash();[Hash(散列)]
? ? *? stringRedisTemplate.opsForZSet();[ZSet(有序集合)]
? ? */public void test(){? ? ? ? stringRedisTemplate.opsForValue().append("msg","hello");? ? }