SpringBoot | 第三十六章:集成多CacheManager


前言

今天有網友咨詢了一個問題:如何在一個工程中使用多種緩存進行差異化緩存,即實現多個cacheManager靈活切換。原來沒有遇見這種場景,今天下班抽空試了下,以下就把如何實現的簡單記錄下。

一點知識

SpringBoot中使用Spring Cache可以輕松實現緩存,是Spring框架提供的對緩存使用的抽象類,支持多種緩存,比如RedisEHCache等,集成很方便。同時提供了多種注解來簡化緩存的使用,可對方法進行緩存。具體如何集成,之前的文章已經有詳細介紹了,感興趣的同學可點擊:SpringBoot | 第十一章:Redis的集成和簡單使用。這里就不再闡述了,一下簡單較少下cacheManager

關於CacheMananger

針對不同的緩存技術,需要實現不同的cacheManager,Spring定義了如下的cacheManger實現。

CacheManger 描述
SimpleCacheManager 使用簡單的Collection來存儲緩存,主要用於測試
ConcurrentMapCacheManager 使用ConcurrentMap作為緩存技術(默認)
NoOpCacheManager 測試用
EhCacheCacheManager 使用EhCache作為緩存技術,以前在hibernate的時候經常用
GuavaCacheManager 使用google guava的GuavaCache作為緩存技術
HazelcastCacheManager 使用Hazelcast作為緩存技術
JCacheCacheManager 使用JCache標准的實現作為緩存技術,如Apache Commons JCS
RedisCacheManager 使用Redis作為緩存技術

常規的SpringBoot已經為我們自動配置了EhCacheCollectionGuavaConcurrentMap等緩存,默認使用ConcurrentMapCacheManagerSpringBootapplication.properties配置文件,使用spring.cache前綴的屬性進行配置。

application配置

spring.cache.type=#緩存的技術類型
spring.cache.cache-names=應用程序啟動創建緩存的名稱
spring.cache.ehcache.config=ehcache的配置文件位置
spring.cache.infinispan.config=infinispan的配置文件位置
spring.cache.jcache.config=jcache配置文件位置
spring.cache.jcache.provider=當多個jcache實現類時,指定選擇jcache的實現類

這里為了演示多cacheManager實現,這里使用redisehcache進行集成。

集成Redis和ehcache

0.pom文件依賴

	    <!-- redis cache -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
		<!-- ehcache緩存 -->
		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache</artifactId>
		</dependency>

1.創建配置類。

CacheConfig.java

/** 
*
* @ClassName   類名:CacheConfig 
* @Description 功能說明:緩存配置類
* <p>
* TODO
*</p>
************************************************************************
* @date        創建日期:2019年3月7日
* @author      創建人:oKong
* @version     版本號:V1.0
*<p>
***************************修訂記錄*************************************
* 
*   2019年3月7日   oKong   創建該類功能。
*
***********************************************************************
*</p>
*/
@Configuration
@EnableCaching
public class CacheConfig {
	
	/**
     * cacheManager名稱
     */
    public interface CacheManagerName {
        /**
         * redis
         */
        String REDIS_CACHE_MANAGER = "redisCacheManager";

        /**
         * ehCache
         */
        String EHCACHE_CACHE_MAANGER = "ehCacheCacheManager";
    }
	/**
     *  定義 StringRedisTemplate ,指定序列號和反序列化的處理類
     * @param factory
     * @return
     */
    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
        StringRedisTemplate template = new StringRedisTemplate(factory);
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(
                Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        //序列化 值時使用此序列化方法
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
    
    @Bean(CacheConfig.CacheManagerName.REDIS_CACHE_MANAGER)
    @Primary
    public RedisCacheManager redisCacheManager(RedisTemplate<String,String> redisTemplate) {
        RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
        //使用前綴
        rcm.setUsePrefix(true);
        //緩存分割符 默認為 ":"
//        rcm.setCachePrefix(new DefaultRedisCachePrefix(":"));
        //設置緩存過期時間
        //rcm.setDefaultExpiration(60);//秒
        return rcm;
    }
	
    @Bean(CacheConfig.CacheManagerName.EHCACHE_CACHE_MAANGER) 
    public EhCacheCacheManager EhcacheManager() {
    	EhCacheCacheManager ehCacheManager = new EhCacheCacheManager();
    	return ehCacheManager;
    }	
}

注:其實就是配置多個cacheManager。但這里需要注意,要設置一個默認的cacheManager,即注解在未設置cacheManager時,自動使用此緩存管理類進行緩存,同時,因為注入了多個cacheManaager,需要在默認的管理器方法上加上@Primary注解。不然,會出現一下異常:

No CacheResolver specified, and no unique bean of type CacheManager found. Mark one as primary (or give it the name 'cacheManager') or declare a specific CacheManager to use, that serves as the default one.

至於原因。可以查看以下代碼:

異常點

其實就是配置了多個bean,拋出了一個NoUniqueBeanDefinitionException異常。其實就是未指定一個默認的cacheManager,所以加上@Primary即可。

@Primary 優先考慮,優先考慮被注解的對象注入

2.編寫測試類,默認是使用redis緩存,若想指定緩存,只需要設置cacheManager的值即可。

/** 
*
* @ClassName   類名:DemoController 
* @Description 功能說明:
* <p>
* TODO
*</p>
************************************************************************
* @date        創建日期:2019年3月7日
* @author      創建人:oKong
* @version     版本號:V1.0
*<p>
***************************修訂記錄*************************************
* 
*   2019年3月7日   oKong   創建該類功能。
*
***********************************************************************
*</p>
*/
@RestController
@Slf4j
public class DemoController {
	
	@RequestMapping("/redis/{key}")
	@Cacheable(value = "redis",key="#key",cacheManager=CacheConfig.CacheManagerName.REDIS_CACHE_MANAGER)
	public String cacheRedisTest(@PathVariable("key") String key) {
		log.info("redis,key={}", key);
		return key;
	}
	
	@RequestMapping("/ehcache/{key}")
	@Cacheable(value = "oKongCache",key="#key",cacheManager=CacheConfig.CacheManagerName.EHCACHE_CACHE_MAANGER)
	public String cacheEhcacheTest(@PathVariable("key") String key) {
		log.info("ehcache,key={}", key);
		return key;
	}
	
	@RequestMapping("/default/{key}")
	@Cacheable(value = "default",key="#key")
	public String cacheDefaultTest(@PathVariable("key") String key) {
		log.info("default,key={}", key);
		return key;
	}
}

3.配置application文件,加入相關配置。

# REDIS (RedisProperties)
# Redis數據庫索引(默認為0)
spring.redis.database=0
# Redis服務器地址
spring.redis.host=127.0.0.1
# Redis服務器連接端口
spring.redis.port=6379
# Redis服務器連接密碼(默認為空)
spring.redis.password=
# 連接池最大連接數(使用負值表示沒有限制)
spring.redis.pool.max-active=8
# 連接池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.pool.max-wait=-1
# 連接池中的最大空閑連接
spring.redis.pool.max-idle=8
# 連接池中的最小空閑連接
spring.redis.pool.min-idle=0
# 連接超時時間(毫秒)
spring.redis.timeout=0

# ehcache配置地址
spring.cache.ehcache.config=ehcache.xml

配置ehcache.xml文件,設置cacheName

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ehcache.xsd">
    <!--timeToIdleSeconds 當緩存閑置n秒后銷毀 -->
    <!--timeToLiveSeconds 當緩存存活n秒后銷毀 -->
    <!-- 緩存配置 
        name:緩存名稱。 
        maxElementsInMemory:緩存最大個數。 
        eternal:對象是否永久有效,一但設置了,timeout將不起作用。 
        timeToIdleSeconds:設置對象在失效前的允許閑置時間(單位:秒)。僅當eternal=false對象不是永久有效時使用,可選屬性,默認值是0,也就是可閑置時間無窮大。 
        timeToLiveSeconds:設置對象在失效前允許存活時間(單位:秒)。最大時間介於創建時間和失效時間之間。僅當eternal=false對象不是永久有效時使用,默認是0.,也就是對象存活時間無窮大。 
        overflowToDisk:當內存中對象數量達到maxElementsInMemory時,Ehcache將會對象寫到磁盤中。 diskSpoolBufferSizeMB:這個參數設置DiskStore(磁盤緩存)的緩存區大小。默認是30MB。每個Cache都應該有自己的一個緩沖區。 
        maxElementsOnDisk:硬盤最大緩存個數。 
        diskPersistent:是否緩存虛擬機重啟期數據 Whether the disk 
        store persists between restarts of the Virtual Machine. The default value 
        is false. 
        diskExpiryThreadIntervalSeconds:磁盤失效線程運行時間間隔,默認是120秒。  memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理內存。默認策略是 
LRU(最近最少使用)。你可以設置為FIFO(先進先出)或是LFU(較少使用)。 
        clearOnFlush:內存數量最大時是否清除。 -->
    <!-- 磁盤緩存位置 -->
    <diskStore path="java.io.tmpdir" />
    <!-- 默認緩存 -->
    <defaultCache 
        maxElementsInMemory="10000" 
        eternal="false"
        timeToIdleSeconds="120" 
        timeToLiveSeconds="120" 
        maxElementsOnDisk="10000000"
        diskExpiryThreadIntervalSeconds="120" 
        memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap" />
    </defaultCache>

    <!-- 指定cache,即對應cacheName的值 -->
    <cache name="oKongCache" 
        eternal="false" 
        timeToIdleSeconds="2400"
        timeToLiveSeconds="2400" 
        maxEntriesLocalHeap="10000"
        maxEntriesLocalDisk="10000000" 
        diskExpiryThreadIntervalSeconds="120"
        overflowToDisk="false" 
        memoryStoreEvictionPolicy="LRU">
    </cache>
</ehcache>

關於其屬性參數,大家可自行百度下,使用的不多呀,(┬_┬)

4.啟動應用。
依次訪問:

  1. http://127.0.0.1:8080/redis/okong
  2. http://127.0.0.1:8080/ehcache/okong
  3. http://127.0.0.1:8080/default/okong

可以看看redis中已經存在相關記錄了

redis

之后多訪問幾次,查看控制台,是沒有輸出的。

console

參考資料

  1. https://docs.spring.io/spring-boot/docs/1.5.15.RELEASE/reference/htmlsingle/#boot-features-caching-provider

總結

本章節主要介紹了多cacheManager的靈活切換,以便實現更加靈活的緩存使用,可以根據具體的業務需求,進行差異化操作。關於ehcache的使用,現在用的不多了,所以相關配置參數,可以自行搜索下了。

最后

目前互聯網上很多大佬都有SpringBoot系列教程,如有雷同,請多多包涵了。原創不易,碼字不易,還希望大家多多支持。若文中有所錯誤之處,還望提出,謝謝。

老生常談

  • 個人QQ:499452441
  • 微信公眾號:lqdevOps

公眾號

個人博客:http://blog.lqdev.cn

完整示例:https://github.com/xie19900123/spring-boot-learning/tree/master/chapter-36

原文地址:https://blog.lqdev.cn/2019/03/08/springboot/chapter-thirty-six/


免責聲明!

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



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