Spring從3.1開始定義了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口來統一不一樣的緩存技術;並支持使用JCache(JSR-107)註解簡化咱們開發;java
Cache接口爲緩存的組件規範定義,包含緩存的各類操做集合;git
Cache接口下Spring提供了各類xxxCache的實現;如RedisCache,EhCacheCache ,ConcurrentMapCache等;github
每次調用須要緩存功能的方法時,Spring會檢查檢查指定參數的指定的目標方法是否已經被調用過;若是有就直接從緩存中獲取方法調用後的結果,若是沒有就調用方法並緩存結果後返回給用戶。下次調用直接從緩存中獲取。正則表達式
使用Spring緩存抽象時咱們須要關注如下兩點;redis
一、肯定方法須要被緩存以及他們的緩存策略spring
二、從緩存中讀取以前緩存存儲的數據數據庫
名稱 | 解釋 |
---|---|
Cache | 緩存接口,定義緩存操做。實現有:RedisCache、EhCacheCache、ConcurrentMapCache等 |
CacheManager | 緩存管理器,管理各類緩存(cache)組件 |
@Cacheable | 主要針對方法配置,可以根據方法的請求參數對其進行緩存 |
@CacheEvict | 清空緩存 |
@CachePut | 保證方法被調用,又但願結果被緩存。 |
與@Cacheable區別在因而否每次都調用方法,經常使用於更新 | |
@EnableCaching | 開啓基於註解的緩存 |
keyGenerator | 緩存數據時key生成策略 |
serialize | 緩存數據時value序列化策略 |
@CacheConfig | 統一配置本類的緩存註解的屬性 |
@Cacheable/@CachePut/@CacheEvict 主要的參數編程
名稱 | 解釋 |
---|---|
value | 緩存的名稱,在 spring 配置文件中定義,必須指定至少一個 |
例如:
@Cacheable(value=」mycache」) 或者
@Cacheable(value={」cache1」,」cache2」} | | key | 緩存的 key,能夠爲空,若是指定要按照 SpEL 表達式編寫,
若是不指定,則缺省按照方法的全部參數進行組合
例如:
@Cacheable(value=」testcache」,key=」#id」) | | condition | 緩存的條件,能夠爲空,使用 SpEL 編寫,返回 true 或者 false,
只有爲 true 才進行緩存/清除緩存
例如:@Cacheable(value=」testcache」,condition=」#userName.length()>2」) | | unless | 否認緩存。當條件結果爲TRUE時,就不會緩存。
@Cacheable(value=」testcache」,unless=」#userName.length()>2」) | | allEntries
(@CacheEvict ) | 是否清空全部緩存內容,缺省爲 false,若是指定爲 true,
則方法調用後將當即清空全部緩存
例如:
@CachEvict(value=」testcache」,allEntries=true) | | beforeInvocation
(@CacheEvict) | 是否在方法執行前就清空,缺省爲 false,若是指定爲 true,
則在方法尚未執行的時候就清空緩存,缺省狀況下,若是方法
執行拋出異常,則不會清空緩存
例如:
@CachEvict(value=」testcache」,beforeInvocation=true) |api
Spring Cache提供了一些供咱們使用的SpEL上下文數據,下表直接摘自Spring官方文檔:緩存
名稱 | 位置 | 描述 | 示例 |
---|---|---|---|
methodName | root對象 | 當前被調用的方法名 | #root.methodname |
method | root對象 | 當前被調用的方法 | #root.method.name |
target | root對象 | 當前被調用的目標對象實例 | #root.target |
targetClass | root對象 | 當前被調用的目標對象的類 | #root.targetClass |
args | root對象 | 當前被調用的方法的參數列表 | #root.args[0] |
caches | root對象 | 當前方法調用使用的緩存列表 | #root.caches[0].name |
Argument Name | 執行上下文 | 當前被調用的方法的參數,如findArtisan(Artisan artisan),能夠經過#artsian.id得到參數 | #artsian.id |
result | 執行上下文 | 方法執行後的返回值(僅當方法執行後的判斷有效,如 unless cacheEvict的beforeInvocation=false) | #result |
注意:
1.當咱們要使用root對象的屬性做爲key時咱們也能夠將「#root」省略,由於Spring默認使用的就是root對象的屬性。 如
@Cacheable(key = "targetClass + methodName +#p0")
2.使用方法參數時咱們能夠直接使用「#參數名」或者「#p參數index」。 如:
@Cacheable(value="users", key="#id")
@Cacheable(value="users", key="#p0")
SpEL提供了多種運算符
類型 | 運算符 |
---|---|
關係 | <,>,<=,>=,==,!=,lt,gt,le,ge,eq,ne |
算術 | +,- ,* ,/,%,^ |
邏輯 | &&, |
條件 | ?: (ternary),?: (elvis) |
正則表達式 | matches |
其餘類型 | ?.,?[…],![…],^[…],$[…] |
以上的知識點適合你遺忘的時候來查閱,下面正式進入學習!
環境:Spring boot 2.0.3
IDE:IDEA
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
@SpringBootApplication @EnableCaching //開啓緩存 public class DemoApplication{ public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
@Cacheable
註解會先查詢是否已經有緩存,有會使用緩存,沒有則會執行方法並緩存。
@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
實體類必定要實現序列化public class User implements Serializable
,不然會報java.io.NotSerializableException
異常。
到這裏,你已經能夠運行程序檢驗緩存功能是否實現。
深刻源碼,查看它的其它屬性
咱們打開@Cacheable
註解的源碼,能夠看到該註解提供的其餘屬性,如:
String[] cacheNames() default {}; //和value註解差很少,二選一
String keyGenerator() default ""; //key的生成器。key/keyGenerator二選一使用
String cacheManager() default ""; //指定緩存管理器
String cacheResolver() default ""; //或者指定獲取解析器
String condition() default ""; //條件符合則緩存
String unless() default ""; //條件符合則不緩存
boolean sync() default false; //是否使用異步模式
當咱們須要緩存的地方愈來愈多,你可使用@CacheConfig(cacheNames = {"myCache"})
註解來統一指定value
的值,這時可省略value
,若是你在你的方法依舊寫上了value
,那麼依然以方法的value
值爲準。
使用方法以下:
@CacheConfig(cacheNames = {"myCache"}) public class BotRelationServiceImpl implements BotRelationService { @Override @Cacheable(key = "targetClass + methodName +#p0")//此處沒寫value public List<BotRelation> findAllLimit(int num) { return botRelationRepository.findAllLimit(num); } ..... }
查看它的其它屬性
String keyGenerator() default ""; //key的生成器。key/keyGenerator二選一使用
String cacheManager() default ""; //指定緩存管理器
String cacheResolver() default ""; //或者指定獲取解析器
@CachePut
註解的做用 主要針對方法配置,可以根據方法的請求參數對其結果進行緩存,和 @Cacheable
不一樣的是,它每次都會觸發真實方法的調用 。簡單來講就是用戶更新緩存數據。但須要注意的是該註解的value
和 key
必須與要更新的緩存相同,也就是與@Cacheable
相同。示例:
@CachePut(value = "emp", key = "targetClass + #p0") public NewJob updata(NewJob job) { NewJob newJob = newJobDao.findAllById(job.getId()); newJob.updata(job); return job; } @Cacheable(value = "emp", key = "targetClass +#p0")//清空緩存 public NewJob save(NewJob job) { newJobDao.save(job); return job; }
查看它的其它屬性
String[] cacheNames() default {}; //與value二選一
String keyGenerator() default ""; //key的生成器。key/keyGenerator二選一使用
String cacheManager() default ""; //指定緩存管理器
String cacheResolver() default ""; //或者指定獲取解析器
String condition() default ""; //條件符合則緩存
String unless() default ""; //條件符合則不緩存
@CachEvict
的做用 主要針對方法配置,可以根據必定的條件對緩存進行清空 。
屬性 | 解釋 | 示例 |
---|---|---|
allEntries | 是否清空全部緩存內容,缺省爲 false,若是指定爲 true,則方法調用後將當即清空全部緩存 | @CachEvict(value=」testcache」,allEntries=true) |
beforeInvocation | 是否在方法執行前就清空,缺省爲 false,若是指定爲 true,則在方法尚未執行的時候就清空緩存,缺省狀況下,若是方法執行拋出異常,則不會清空緩存 | @CachEvict(value=」testcache」,beforeInvocation=true) |
示例:
@Cacheable(value = "emp",key = "#p0.id") public NewJob save(NewJob job) { newJobDao.save(job); return job; } //清除一條緩存,key爲要清空的數據 @CacheEvict(value="emp",key="#id") public void delect(int id) { newJobDao.deleteAllById(id); } //方法調用後清空全部緩存 @CacheEvict(value="accountCache",allEntries=true) public void delectAll() { newJobDao.deleteAll(); } //方法調用前清空全部緩存 @CacheEvict(value="accountCache",beforeInvocation=true) public void delectAll() { newJobDao.deleteAll(); }
其餘屬性
String[] cacheNames() default {}; //與value二選一
String keyGenerator() default ""; //key的生成器。key/keyGenerator二選一使用
String cacheManager() default ""; //指定緩存管理器
String cacheResolver() default ""; //或者指定獲取解析器
String condition() default ""; //條件符合則清空
有時候咱們可能組合多個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) { .... }
下面講到的整合第三方緩存組件都是基於上面的已經完成的步驟,因此一個應用要先作好你的緩存邏輯,再來整合其餘cache組件。
Ehcache是一種普遍使用的開源Java分佈式緩存。主要面向通用緩存,Java EE和輕量級容器。它具備內存和磁盤存儲,緩存加載器,緩存擴展,緩存異常處理程序,一個gzip緩存servlet過濾器,支持REST和SOAP api等特色。
整合ehcache必需要導入它的依賴。
<dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
須要說明的是config: classpath:/ehcache.xml
能夠不用寫,由於默認就是這個路徑。但ehcache.xml
必須有。
spring: cache: type: ehcache ehcache: config: classpath:/ehcache.xml
在resources目錄下新建ehcache.xml,註釋啥的應該能夠說至關詳細了
<ehcache> <!-- 磁盤存儲:將緩存中暫時不使用的對象,轉移到硬盤,相似於Windows系統的虛擬內存 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:設置了緩存的上限,最多存儲多少個記錄對象 eternal:表明對象是否永不過時 (指定true則下面兩項配置需爲0無限期) timeToIdleSeconds:最大的發呆時間 /秒 timeToLiveSeconds:最大的存活時間 /秒 overflowToDisk:是否容許對象被寫入到磁盤 說明:下列配置自緩存創建起600秒(10分鐘)有效 。 在有效的600秒(10分鐘)內,若是連續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>
@CacheConfig(cacheNames = {「myCache」})
設置ehcache的名稱,這個名稱必須在ehcache.xml已配置 。
@CacheConfig(cacheNames = {"myCache"}) public class BotRelationServiceImpl implements BotRelationService { @Cacheable(key = "targetClass + methodName +#p0") public List<BotRelation> findAllLimit(int num) { return botRelationRepository.findAllLimit(num); } }
整合完畢!
別忘了在啓動類開啓緩存!
Redis 優點
下載地址:https://github.com/MicrosoftArchive/redis/releases
就只須要這一個依賴!不須要spring-boot-starter-cache
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
當你導入這一個依賴時,SpringBoot的CacheManager就會使用RedisCache。
若是你的Redis使用默認配置,這時候已經能夠啓動程序了。
# Redis數據庫索引(默認爲0) spring.redis.database=1 # Redis服務器地址 spring.redis.host=127.0.0.1 # Redis服務器鏈接端口 spring.redis.port=6379 # Redis服務器鏈接密碼(默認爲空) spring.redis.password= # 鏈接池最大鏈接數(使用負值表示沒有限制) 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
除了使用註解,咱們還可使用Redis模板。
Spring boot集成 Redis 客戶端jedis。封裝Redis 鏈接池,以及操做模板。
@Autowired private StringRedisTemplate stringRedisTemplate;//操做key-value都是字符串 @Autowired private RedisTemplate redisTemplate;//操做key-value都是對象 /** * Redis常見的五大數據類型: * stringRedisTemplate.opsForValue();[String(字符串)] * stringRedisTemplate.opsForList();[List(列表)] * stringRedisTemplate.opsForSet();[Set(集合)] * stringRedisTemplate.opsForHash();[Hash(散列)] * stringRedisTemplate.opsForZSet();[ZSet(有序集合)] */ public void test(){ stringRedisTemplate.opsForValue().append("msg","hello"); }