史上最全面的Spring Boot Cache使用與整合
一:Spring快取抽象
Spring從3.1開始定義了org.springframework.cache.Cache和org.springframework.cache.CacheManager介面來統一不同的快取技術;並支援使用JCache(JSR-107)註解簡化我們開發;
-
Cache介面為快取的元件規範定義,包含快取的各種操作集合;
-
Cache介面下Spring提供了各種xxxCache的實現;如RedisCache,EhCacheCache ,ConcurrentMapCache等;
-
每次呼叫需要快取功能的方法時,Spring會檢查檢查指定引數的指定的目標方法是否已經被呼叫過;如果有就直接從快取中獲取方法呼叫後的結果,如果沒有就呼叫方法並快取結果後返回給使用者。下次呼叫直接從快取中獲取。
-
使用Spring快取抽象時我們需要關注以下兩點;
1、確定方法需要被快取以及他們的快取策略
2、從快取中讀取之前快取儲存的資料
二:幾個重要概念&快取註解
名稱 | 解釋 |
---|---|
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) |
三:SpEL上下文資料
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 |
算術 | +,- ,* ,/,%,^ |
邏輯 | &&,||,!,and,or,not,between,instanceof |
條件 | ?: (ternary),?: (elvis) |
正規表示式 | matches |
其他型別 | ?.,?[…],![…],^[…],$[…] |
以上的知識點適合你遺忘的時候來查閱,下面正式進入學習!
四:開始使用
環境: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 //開啟快取
public class DemoApplication{
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
3.快取@Cacheable
@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; //是否使用非同步模式
4.配置@CacheConfig
當我們需要快取的地方越來越多,你可以使用@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 ""; //或者指定獲取解析器
5.更新@CachePut
@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 ""; //條件符合則不快取
6.清除@CacheEvict
@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 ""; //條件符合則清空
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) {
....
}
下面講到的整合第三方快取元件都是基於上面的已經完成的步驟,所以一個應用要先做好你的快取邏輯,再來整合其他cache元件。
五:整合EHCACHE
Ehcache是一種廣泛使用的開源Java分散式快取。主要面向通用快取,Java EE和輕量級容器。它具有記憶體和磁碟儲存,快取載入器,快取擴充套件,快取異常處理程式,一個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: ehcache
ehcache:
config: classpath:/ehcache.xml
3.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>
4.使用快取
@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
Redis 優勢
- 效能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s 。
- 豐富的資料型別 – Redis支援二進位制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 資料型別操作。
- 原子 – Redis的所有操作都是原子性的,意思就是要麼成功執行要麼失敗完全不執行。單個操作是原子性的。多個操作也支援事務,即原子性,通過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使用預設配置,這時候已經可以啟動程式了。
3.配置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
4.模板程式設計
除了使用註解,我們還可以使用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");
}
相關文章
- Spring Cache + Caffeine的整合與使用Spring
- Spring Cache與Ehcache 3整合Spring
- Spring Boot(十八):使用 Spring Boot 整合 FastDFSSpring BootAST
- ElasticSearch與Spring Boot整合ElasticsearchSpring Boot
- 史上最全面的React-react基礎React
- Solr與Spring Boot整合 - ViithiisysSolrSpring Boot
- Spring Boot 2.X(七):Spring Cache 使用Spring Boot
- 使用Spring Boot整合ConsulSpring Boot
- OPPO A59史上最全面的體驗評測
- 史上最全面的程式設計師招聘建議程式設計師
- 使用Spring Boot整合Apollo配置中心Spring Boot
- Spring Boot 與 R2DBC 整合Spring Boot
- Spring Boot(十三)RabbitMQ安裝與整合Spring BootMQ
- Spring Boot整合swagger使用教程Spring BootSwagger
- Spring Boot Cache Redis快取Spring BootRedis快取
- Spring Boot 2.0(八):Spring Boot 整合 MemcachedSpring Boot
- 學習筆記:cache 和spring cache 技術2--spring cache 的基本使用 、spring-Redis整合筆記SpringRedis
- Spring Boot整合rabbitmqSpring BootMQ
- Spring Boot 整合 rabbitmqSpring BootMQ
- Spring Boot 整合 elasticsearchSpring BootElasticsearch
- Spring Boot 整合 dockerSpring BootDocker
- Spring Boot 整合 elkSpring Boot
- Spring Boot 整合 ApolloSpring Boot
- Spring Boot整合RedisSpring BootRedis
- Spring Boot 整合redisSpring BootRedis
- Spring Boot 整合 MyBatisSpring BootMyBatis
- Spring Boot整合SocketSpring Boot
- spring boot整合jooqSpring Boot
- Spring Boot 整合 KafkaSpring BootKafka
- spring boot 整合mybatisSpring BootMyBatis
- Spring Boot整合Spring BatchSpring BootBAT
- Spring Boot整合Spring SecuritySpring Boot
- Spring Boot整合Spring AopSpring Boot
- RabbitMQ(三):RabbitMQ與Spring Boot簡單整合MQSpring Boot
- Spring boot學習(三) Spring boot整合mybatisSpring BootMyBatis
- Spring Boot 3中將JWT與Spring Security 6整合Spring BootJWT
- Spring Cache的基本使用與分析Spring
- 最全面的 Spring 學習筆記Spring筆記