SpringBoot進階篇4:Spring Boot EHCache應用
1、SpringBoot Cache
Spring Boot 本身提供了一個基於ConcurrentHashMap 的快取機制,也集成了EhCache2.x、JCache CJSR-107、EhCache3.x、Infinispan ),還有Couchbase、Redis 等。Spring Boot應用通過註解的方式使用統一的快取,只需在方法上使用快取註解即可。
1.1、Spring Boot Cache常用註解說明
一旦配置好Spring Boot 快取,就可以在Spring管理的Bean 中使用快取註解,通常可以直接放在Service 類上。
@Cacheable
@CacheEvict:作用在方法上,觸發快取失效操作。
@CachePut:作用在方法上,觸發快取更新操作。
@Cache:作用在方法上,綜合上面的各種操作,在有些場景下,呼叫業務會觸發多種快取操作。
@CacheConfig,在類上設定當前快取的一些公共設定。
1.2、Cache中key生成器
快取的Key非常重要,Spring使用SimpleKeyGenerator來實現上述Key的生。
package org.springframework.cache.interceptor; import java.lang.reflect.Method; //SimpleKeyGenerator類繼承KeyGenerator介面 public class SimpleKeyGenerator implements KeyGenerator { @Override public Object generate(Object target, Method method, Object... params) { return generateKey(params); } /** * SimpleKey 實現了hash Code 和equals 方法: */ public static Object generateKey(Object... params) { if (params.length == 0) { return SimpleKey.EMPTY; } if (params.length == 1) { Object param = params[0]; if (param != null && !param.getClass().isArray()) { return param; } } return new SimpleKey(params); } }
【注意】 通常生產環境情況下,直接使用SpEL表示式來指定Key 比自定義一個KeyGenerator更為簡單:
1.3、註解詳解
【@Cacheable支援如下幾個引數】
(1)value:快取位置名稱,不能為空,如果使用EHCache,就是ehcache.xml中宣告的cache的name。
(2)key:快取的key,預設為空,既表示使用方法的引數型別及引數值作為key,支援SpEL。
(3)condition:觸發條件,只有滿足條件的情況才會加入快取,預設為空,既表示全部都加入快取,支援SpEL。
【@CacheEvict支援如下幾個引數】
(1)value:快取位置名稱,不能為空,同上
(2)key:快取的key,預設為空,同上
(3)condition:觸發條件,只有滿足條件的情況才會清除快取,預設為空,支援SpEL
(4)allEntries:true表示清除value中的全部快取,預設為false。
【@CachePut註釋】
@CachePut註釋,這個註釋可以確保方法被執行,同時方法的返回值也被記錄到快取中,實現快取與資料庫的同步更新,理解為update語句。
2、Spring Boot EHCache應用
2.1、引入pom
<!--開啟 cache 快取-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--ehcache快取,依賴spring-context-support包-->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.8.3</version>
</dependency>
<!-- 該依賴必須加,裡面spring支援schedule的支援,以及ehcache快取-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
2.2、ehcache.xml配置檔案
ehcache.xml配置檔案是位於resources資原始檔下
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<!-- diskStore:ehcache其實是支援記憶體+磁碟+堆外記憶體,幾個層級的快取 -->
<!-- 在這裡設定一下,但是一般不用的 -->
<diskStore path="java.io.tmpdir/Tmp_EhCache" />
<!-- defaultCache,是預設的快取策略 -->
<!-- 如果你指定的快取策略沒有找到,那麼就用這個預設的快取策略 -->
<!-- external:如果設定為true的話,那麼timeout就沒有效果,快取就會一直存在,一般預設就是false -->
<!-- maxElementsInMemory:記憶體中可以快取多少個快取條目,在實踐中,你是需要自己去計算的,比如你計算你要快取的物件是什麼?有多大?最多可以快取多少MB,或者多少個G的資料?除以每個物件的大小,計算出最多可以放多少個物件 -->
<!-- overflowToDisk:如果記憶體不夠的時候,是否溢位到磁碟 -->
<!-- diskPersistent:是否啟用磁碟持久化的機制,在jvm崩潰的時候和重啟之間,不用 -->
<!-- timeToIdleSeconds:物件最大的閒置的時間,如果超出閒置的時間,可能就會過期,我們這裡就不用了,快取最多閒置5分鐘就被幹掉了 -->
<!-- timeToLiveSeconds:物件最多存活的時間,我們這裡也不用,超過這個時間,快取就過期,就沒了 -->
<!-- memoryStoreEvictionPolicy:當快取數量達到了最大的指定條目數的時候,需要採用一定的演算法,從快取中清除一批資料,LRU,最近最少使用演算法,最近一段時間內,最少使用的那些資料,就被幹掉了 -->
<defaultCache
eternal="false"
maxElementsInMemory="50000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="300"
timeToLiveSeconds="0"
memoryStoreEvictionPolicy="LRU" />
<!-- 手動指定的快取策略 -->
<!-- 比如你一個應用吧,可能要快取很多種不同的資料,比如說商品資訊,或者是其他的一些資料 -->
<!-- 對不同的資料,快取策略可以在這裡配置多種 -->
<cache
name="deptCache"
eternal="false"
maxElementsInMemory="10000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="300"
timeToLiveSeconds="0"
memoryStoreEvictionPolicy="LRU" />
<cache
name="yearCache"
eternal="false"
maxElementsInMemory="1000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="300"
timeToLiveSeconds="0"
memoryStoreEvictionPolicy="LRU" />
<cache
name="quotaCache"
eternal="false"
maxElementsInMemory="50000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="300"
timeToLiveSeconds="0"
memoryStoreEvictionPolicy="LRU" />
<!-- ehcache這種東西,簡單實用,是很快速的,1小時上手可以用在專案裡了,沒什麼難度的 -->
<!-- ehcache這個技術,如果講深了,裡面的東西還是很多的,高階的feature,但是我們這裡就不涉及了 -->
</ehcache>
2.3、EhCache配置類
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
/**
* ehcache快取
*/
@Configuration
@EnableCaching//標註啟動了encache快取
public class EhCacheConfig
{
/**
* EhCacheManagerFactoryBean快取管理器,預設的為EhCacheCacheManager
* Spring分別通過CacheManager.create()和new CacheManager方式來建立一個ehcache工廠
* 一個EhCacheManagerFactoryBean建立完成, 也就代表著一個CacheManager
*/
@Bean
public EhCacheManagerFactoryBean ehCacheManagerFactoryBean(){
EhCacheManagerFactoryBean cacheManagerFactoryBean = new EhCacheManagerFactoryBean();
cacheManagerFactoryBean.setConfigLocation(new ClassPathResource("ehcache.xml"));
cacheManagerFactoryBean.setShared(true);
return cacheManagerFactoryBean;
}
/**
* ehcache 主要的管理器
*/
@Bean
public EhCacheCacheManager ehCacheCacheManager(EhCacheManagerFactoryBean bean){
return new EhCacheCacheManager(bean.getObject());
}
}
2.4、應用
public static final String CACHE_NAME = "deptCache";
/**
* 查詢部門列表
*
* @return
*/
@Cacheable(value = CACHE_NAME, key = "'key_deptList'")
@Override
public List<Dept> deptList()
{
return this.baseMapper.deptList();
}
/**
* 部門ztree樹
* @return
*/
@Cacheable(value = CACHE_NAME, key = "'key_deptTree'")
@Override
public List<ZTreeNode> zTree(){
/* List<ZTreeNode> zTreeNodes=tree();
zTreeNodes.add(ZTreeNode.createParent("區域選擇"));*/
return tree();
}
@CachePut(value = CACHE_NAME, key = "'key_deptTree'")
@Override
public List<ZTreeNode> zTreeInit(){
/* List<ZTreeNode> zTreeNodes=tree();
zTreeNodes.add(ZTreeNode.createParent("區域選擇"));*/
return tree();
}
private List<ZTreeNode> tree(){
List<ZTreeNode> tree = this.baseMapper.tree();
return tree;
}
@CacheEvict(value = CACHE_NAME, key = "'key_deptTree'")
@Override
public void EmptyCache(){
}