1. 程式人生 > >SpringBoot進階篇4:Spring Boot EHCache應用

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(){

    }