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,查找对应的缓存。