史上最全的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運行會報錯,觀察它們的返回類型,原因在於methodNameStringmethohMethod

此處的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"); }

作者: 薛勤

出處:https://www.cnblogs.com/yueshutong/p/9381540.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM