http://tramp.cincout.cn/2017/10/31/spring-boot-2017-10-31-spring-boot-multi-cache-manager/java
這個要看項目實際須要。一種場景就是有部分數據只是各個服務實例本身須要,因此用本地緩存(如Guava、EhCache)便可,這樣也方便簡潔;而同時有的數據須要各個服務實例共享,這種數據就適合存儲於分佈式緩存中(如Redis)。web
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.ding.data</groupId> <artifactId>serverlCacheCase</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <boot.version>1.3.5.RELEASE</boot.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${boot.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <version>${boot.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> <version>${boot.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> <version>${boot.version}</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>19.0</version> </dependency> </dependencies> </project>
spring: #cache: #緩存名稱 #cache-names: guavaDemo #緩存最大數量500條, 緩存失效時間 6個小時 #guava.spec: maximumSize=500,expireAfterWrite=360m # REDIS (RedisProperties) redis : host : localhost # server host port : 6379 # connection port password : 123 pool.max-idle : 8 # pool settings ... pool.min-idle : 1 pool.max-active : 8 pool.max-wait : -1
package com.ding.data.config; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; import javax.annotation.Resource; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.cache.CacheManager; import org.springframework.cache.guava.GuavaCacheManager; import org.springframework.cache.support.CompositeCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; import com.google.common.cache.CacheBuilder; import com.google.common.collect.Lists; @Configuration public class CacheConfig implements ApplicationRunner { @Resource private List<CacheManager> cacheManagers; public void run(ApplicationArguments args) throws Exception { System.out.println("CacheManager大小爲=========" + cacheManagers.size()); System.out.println("================================================="); for(CacheManager c:cacheManagers){ System.out.println(c.getCacheNames()); } } @Bean(name = "redisCacheManager") public RedisCacheManager redisCacheManager( RedisTemplate<Object, Object> redisTemplate) { redisTemplate.setKeySerializer(new StringRedisSerializer()); RedisCacheManager redisCacheManager = new RedisCacheManager( redisTemplate); redisCacheManager.setCacheNames(Arrays.asList("redisDemo")); redisCacheManager.setUsePrefix(true); return redisCacheManager; } @Bean(name = "guavaCacheManager") public GuavaCacheManager getGuavaCacheManager() { GuavaCacheManager guavaCacheManager = new GuavaCacheManager(); guavaCacheManager.setCacheBuilder(CacheBuilder.newBuilder() .expireAfterWrite(3600, TimeUnit.SECONDS).maximumSize(1000)); ArrayList<String> guavaCacheNames = Lists.newArrayList(); guavaCacheNames.add("guavaDemo"); guavaCacheManager.setCacheNames(guavaCacheNames); return guavaCacheManager; } @Bean(name = "cacheManager") @Primary public CompositeCacheManager cacheManager( RedisCacheManager redisCacheManager, GuavaCacheManager guavaCacheManager) { CompositeCacheManager cacheManager = new CompositeCacheManager( redisCacheManager, guavaCacheManager); return cacheManager; } }
package com.ding.data.cache; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.annotation.PostConstruct; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @Service //@CacheConfig(cacheManager = "guavaCacheManager") public class GuavaDataCache { private Map<Long, String> dataMap = new HashMap<Long, String>(); /** * 初始化 */ @PostConstruct public void init() { dataMap.put(1L, "張三"); dataMap.put(2L, "李四"); dataMap.put(3L, "王五"); } /** * 查詢 * 若是數據沒有緩存,那麼從dataMap裏面獲取,若是緩存了, * 那麼從guavaDemo裏面獲取 * 而且將緩存的數據存入到 guavaDemo裏面 * 其中key 爲 #id+dataMap */ @Cacheable(value="guavaDemo" ,key="#id + 'dataMap'") public String query(Long id) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(sdf.format(new Date()) + " : query id is " + id); return dataMap.get(id); } /** * 插入 或者更新 * 插入或更新數據到dataMap中 * 而且緩存到 guavaDemo中 * 若是存在了那麼更新緩存中的值 * 其中key 爲 #id+dataMap */ @CachePut(value="guavaDemo" ,key="#id + 'dataMap'") public String put(Long id, String value) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(sdf.format(new Date()) + " : add data ,id is "+ id); dataMap.put(id, value); // data persistence return value; } /** * 刪除 * 刪除dataMap裏面的數據 * 而且刪除緩存guavaDemo中的數據 * 其中key 爲 #id+dataMap */ @CacheEvict(value="guavaDemo" , key="#id + 'dataMap'") public void remove(Long id) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(sdf.format(new Date()) + " : remove id is "+ id + " data"); dataMap.remove(id); // data remove } }
package com.ding.data.cache; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.annotation.PostConstruct; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @Service //@CacheConfig(cacheManager = "redisCacheManager") public class RedisDataCache { private Map<Long, String> dataMap = new HashMap<Long, String>(); /** * 初始化 */ @PostConstruct public void init() { dataMap.put(1L, "111"); dataMap.put(2L, "222"); dataMap.put(3L, "333"); } /** * 查詢 * 若是數據沒有緩存,那麼從dataMap裏面獲取,若是緩存了, * 那麼從guavaDemo裏面獲取 * 而且將緩存的數據存入到 guavaDemo裏面 * 其中key 爲 #id+dataMap */ @Cacheable(value="redisDemo" ,key="#id + 'dataMap'") public String query(Long id) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(sdf.format(new Date()) + " : query id is " + id); return dataMap.get(id); } /** * 插入 或者更新 * 插入或更新數據到dataMap中 * 而且緩存到 guavaDemo中 * 若是存在了那麼更新緩存中的值 * 其中key 爲 #id+dataMap */ @CachePut(value="redisDemo" ,key="#id + 'dataMap'") public String put(Long id, String value) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(sdf.format(new Date()) + " : add data ,id is "+ id); dataMap.put(id, value); // data persistence return value; } /** * 刪除 * 刪除dataMap裏面的數據 * 而且刪除緩存guavaDemo中的數據 * 其中key 爲 #id+dataMap */ @CacheEvict(value="redisDemo" , key="#id + 'dataMap'") public void remove(Long id) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(sdf.format(new Date()) + " : remove id is "+ id + " data"); dataMap.remove(id); // data remove } }
package com.ding.data; import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ding.data.cache.GuavaDataCache; import com.ding.data.cache.RedisDataCache; /** * 是Spring Boot項目的核心註解,主要是開啓自動配置 */ @SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan @RestController // 開啓緩存 @EnableCaching public class App { @Autowired private GuavaDataCache dataCache; @Autowired private RedisDataCache rdataCache; public static void main(String[] args) { SpringApplication.run(App.class, args); } @RequestMapping("/put") public String put(Long id, String value) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(new Date()) + " : value is " + dataCache.put(id, value); } @RequestMapping("/get") public String query(Long id) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(new Date()) + " : value is " + dataCache.query(id); } @RequestMapping("/remove") public String remove(Long id) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); dataCache.remove(id); return sdf.format(new Date()) + " : success "; } @RequestMapping("/putr") public String putr(Long id, String value) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(new Date()) + " : value is " + rdataCache.put(id, value); } @RequestMapping("/getr") public String queryr(Long id) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(new Date()) + " : value is " + rdataCache.query(id); } @RequestMapping("/remover") public String remover(Long id) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); rdataCache.remove(id); return sdf.format(new Date()) + " : success "; } }
訪問redis
http://localhost:8080/getr?id=1spring
查看Redis服務器中,以下apache
可見緩存
/getr?id=1服務器
這個連接返回時將數據寫入了Redis服務器中。app
訪問maven
http://localhost:8080/putr?id=1&value=999999分佈式
而後查看Redis服務器,以下圖
訪問
http://localhost:8080/get?id=1
而後調用
http://localhost:8080/put?id=1&value=777777
查看Redis中的值,並未發生任何改變。說明redis緩存和guava緩存互不干擾,都按照設想的進行了正確的訪問。爲何這麼說?由於以前試過別的配置,結果發現緩存發生了混亂,而如今正常,說明如今的配置類文件和相關的配置信息都寫正確了。
項目啓動過程當中打印以下。ApplicationRunner接口的具體用法能夠自行百度。實現ApplicationRunner接口並非必須的,這裏就是爲了啓動時打印展現CacheManager。
從圖中能夠看到被 @Bean 註解的三個CachaManager都加進了 cacheManagers 中。
Spring Cache在 CacheManager 之下能夠採用緩存名稱(cacheNames 屬性)來對緩存進行區分。Spring Cache 提供了CompositeCacheManager 來對全部的 CacheManager 進行代理。根據指定的cacheName 去遍歷全部的 CacheManager,查找對應的緩存。