前言

今天有网友咨询了一个问题:如何在一个工程中使用多种缓存进行差异化缓存,即实现多个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配置

  1. spring.cache.type=#缓存的技术类型
  2. spring.cache.cache-names=应用程序启动创建缓存的名称
  3. spring.cache.ehcache.config=ehcache的配置文件位置
  4. spring.cache.infinispan.config=infinispan的配置文件位置
  5. spring.cache.jcache.config=jcache配置文件位置
  6. spring.cache.jcache.provider=当多个jcache实现类时,指定选择jcache的实现类

这里为了演示多cacheManager实现,这里使用redisehcache进行集成。

集成Redis和ehcache

0.pom文件依赖

  1. <!-- redis cache -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-data-redis</artifactId>
  5. </dependency>
  6. <!-- ehcache缓存 -->
  7. <dependency>
  8. <groupId>net.sf.ehcache</groupId>
  9. <artifactId>ehcache</artifactId>
  10. </dependency>

1.创建配置类。

CacheConfig.java

  1. /**
  2. *
  3. * @ClassName 类名:CacheConfig
  4. * @Description 功能说明:缓存配置类
  5. * <p>
  6. * TODO
  7. *</p>
  8. ************************************************************************
  9. * @date 创建日期:2019年3月7日
  10. * @author 创建人:oKong
  11. * @version 版本号:V1.0
  12. *<p>
  13. ***************************修订记录*************************************
  14. *
  15. * 2019年3月7日 oKong 创建该类功能。
  16. *
  17. ***********************************************************************
  18. *</p>
  19. */
  20. @Configuration
  21. @EnableCaching
  22. public class CacheConfig {
  23. /**
  24. * cacheManager名称
  25. */
  26. public interface CacheManagerName {
  27. /**
  28. * redis
  29. */
  30. String REDIS_CACHE_MANAGER = "redisCacheManager";
  31. /**
  32. * ehCache
  33. */
  34. String EHCACHE_CACHE_MAANGER = "ehCacheCacheManager";
  35. }
  36. /**
  37. * 定义 StringRedisTemplate ,指定序列号和反序列化的处理类
  38. * @param factory
  39. * @return
  40. */
  41. @Bean
  42. public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
  43. StringRedisTemplate template = new StringRedisTemplate(factory);
  44. Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(
  45. Object.class);
  46. ObjectMapper om = new ObjectMapper();
  47. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  48. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  49. jackson2JsonRedisSerializer.setObjectMapper(om);
  50. //序列化 值时使用此序列化方法
  51. template.setValueSerializer(jackson2JsonRedisSerializer);
  52. template.afterPropertiesSet();
  53. return template;
  54. }
  55. @Bean(CacheConfig.CacheManagerName.REDIS_CACHE_MANAGER)
  56. @Primary
  57. public RedisCacheManager redisCacheManager(RedisTemplate<String,String> redisTemplate) {
  58. RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
  59. //使用前缀
  60. rcm.setUsePrefix(true);
  61. //缓存分割符 默认为 ":"
  62. // rcm.setCachePrefix(new DefaultRedisCachePrefix(":"));
  63. //设置缓存过期时间
  64. //rcm.setDefaultExpiration(60);//秒
  65. return rcm;
  66. }
  67. @Bean(CacheConfig.CacheManagerName.EHCACHE_CACHE_MAANGER)
  68. public EhCacheCacheManager EhcacheManager() {
  69. EhCacheCacheManager ehCacheManager = new EhCacheCacheManager();
  70. return ehCacheManager;
  71. }
  72. }

注:其实就是配置多个cacheManager。但这里需要注意,要设置一个默认的cacheManager,即注解在未设置cacheManager时,自动使用此缓存管理类进行缓存,同时,因为注入了多个cacheManaager,需要在默认的管理器方法上加上@Primary注解。不然,会出现一下异常:

  1. 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即可。

  1. @Primary 优先考虑,优先考虑被注解的对象注入

2.编写测试类,默认是使用redis缓存,若想指定缓存,只需要设置cacheManager的值即可。

  1. /**
  2. *
  3. * @ClassName 类名:DemoController
  4. * @Description 功能说明:
  5. * <p>
  6. * TODO
  7. *</p>
  8. ************************************************************************
  9. * @date 创建日期:2019年3月7日
  10. * @author 创建人:oKong
  11. * @version 版本号:V1.0
  12. *<p>
  13. ***************************修订记录*************************************
  14. *
  15. * 2019年3月7日 oKong 创建该类功能。
  16. *
  17. ***********************************************************************
  18. *</p>
  19. */
  20. @RestController
  21. @Slf4j
  22. public class DemoController {
  23. @RequestMapping("/redis/{key}")
  24. @Cacheable(value = "redis",key="#key",cacheManager=CacheConfig.CacheManagerName.REDIS_CACHE_MANAGER)
  25. public String cacheRedisTest(@PathVariable("key") String key) {
  26. log.info("redis,key={}", key);
  27. return key;
  28. }
  29. @RequestMapping("/ehcache/{key}")
  30. @Cacheable(value = "oKongCache",key="#key",cacheManager=CacheConfig.CacheManagerName.EHCACHE_CACHE_MAANGER)
  31. public String cacheEhcacheTest(@PathVariable("key") String key) {
  32. log.info("ehcache,key={}", key);
  33. return key;
  34. }
  35. @RequestMapping("/default/{key}")
  36. @Cacheable(value = "default",key="#key")
  37. public String cacheDefaultTest(@PathVariable("key") String key) {
  38. log.info("default,key={}", key);
  39. return key;
  40. }
  41. }

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

  1. # REDIS (RedisProperties)
  2. # Redis数据库索引(默认为0)
  3. spring.redis.database=0
  4. # Redis服务器地址
  5. spring.redis.host=127.0.0.1
  6. # Redis服务器连接端口
  7. spring.redis.port=6379
  8. # Redis服务器连接密码(默认为空)
  9. spring.redis.password=
  10. # 连接池最大连接数(使用负值表示没有限制)
  11. spring.redis.pool.max-active=8
  12. # 连接池最大阻塞等待时间(使用负值表示没有限制)
  13. spring.redis.pool.max-wait=-1
  14. # 连接池中的最大空闲连接
  15. spring.redis.pool.max-idle=8
  16. # 连接池中的最小空闲连接
  17. spring.redis.pool.min-idle=0
  18. # 连接超时时间(毫秒)
  19. spring.redis.timeout=0
  20. # ehcache配置地址
  21. spring.cache.ehcache.config=ehcache.xml

配置ehcache.xml文件,设置cacheName

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:noNamespaceSchemaLocation="ehcache.xsd">
  4. <!--timeToIdleSeconds 当缓存闲置n秒后销毁 -->
  5. <!--timeToLiveSeconds 当缓存存活n秒后销毁 -->
  6. <!-- 缓存配置
  7. name:缓存名称。
  8. maxElementsInMemory:缓存最大个数。
  9. eternal:对象是否永久有效,一但设置了,timeout将不起作用。
  10. timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
  11. timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
  12. overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。 diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
  13. maxElementsOnDisk:硬盘最大缓存个数。
  14. diskPersistent:是否缓存虚拟机重启期数据 Whether the disk
  15. store persists between restarts of the Virtual Machine. The default value
  16. is false.
  17. diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。 memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是
  18. LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
  19. clearOnFlush:内存数量最大时是否清除。 -->
  20. <!-- 磁盘缓存位置 -->
  21. <diskStore path="java.io.tmpdir" />
  22. <!-- 默认缓存 -->
  23. <defaultCache
  24. maxElementsInMemory="10000"
  25. eternal="false"
  26. timeToIdleSeconds="120"
  27. timeToLiveSeconds="120"
  28. maxElementsOnDisk="10000000"
  29. diskExpiryThreadIntervalSeconds="120"
  30. memoryStoreEvictionPolicy="LRU">
  31. <persistence strategy="localTempSwap" />
  32. </defaultCache>
  33. <!-- 指定cache,即对应cacheName的值 -->
  34. <cache name="oKongCache"
  35. eternal="false"
  36. timeToIdleSeconds="2400"
  37. timeToLiveSeconds="2400"
  38. maxEntriesLocalHeap="10000"
  39. maxEntriesLocalDisk="10000000"
  40. diskExpiryThreadIntervalSeconds="120"
  41. overflowToDisk="false"
  42. memoryStoreEvictionPolicy="LRU">
  43. </cache>
  44. </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中已经存在相关记录了

之后多访问几次,查看控制台,是没有输出的。

参考资料

  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/

SpringBoot | 第三十六章:集成多CacheManager的更多相关文章

  1. Gradle 1.12用户指南翻译——第三十六章. Sonar Runner 插件

    本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  2. “全栈2019”Java第三十六章:类

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  3. SpringBoot | 第三十五章:Mybatis的集成和使用

    前言 最近收到公众号留言说,单纯的Mybatis的集成和使用.前面在第九章:Mybatis-plus的集成和使用介绍了基于mybatis-plus的集成和使用.后者也只是对mybatis进行了功能增强 ...

  4. SpringBoot | 第三十二章:事件的发布和监听

    前言 今天去官网查看spring boot资料时,在特性中看见了系统的事件及监听章节.想想,spring的事件应该是在3.x版本就发布的功能了,并越来越完善,其为bean和bean之间的消息通信提供了 ...

  5. “全栈2019”Java多线程第三十六章:如何设置线程的等待截止时间

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 下一章 "全栈2019"J ...

  6. SpringBoot | 第三十四章:CXF构建WebService服务

    前言 上一章节,讲解了如何使用Spring-WS构建WebService服务.其实,创建WebService的方式有很多的,今天来看看如何使用apache cxf来构建及调用WebService服务. ...

  7. 【WPF学习】第三十六章 样式基础

    前面三章介绍了WPF资源系统,使用资源可在一个地方定义对象而在整个标记中重用他们.尽管可使用资源存储各种对象,但使用资源最常见的原因之一是通过他们的保存样式. 样式是可应用于元素的属性值集合.WPF样 ...

  8. 第三十六章 Linux常用性能检测的指令

    作为一个Linux运维人员,介绍下常用的性能检测指令! 一.uptime 命令返回的信息: 19:08:17              //系统当前时间 up 127 days,  3:00     ...

  9. 第三十六章 metrics(4)- metrics-graphite

    将metrics report给graphite(carbon-relay) 一.代码 1.pom.xml <!-- metrics-graphite --> <dependency ...

随机推荐

  1. 两款Mongodb可视化工具

    在某些场景下,相比传统的关系数据库和NoSQL数据库,Mongodb拥有不可替代的优势. 例如,最近我需要为收集的大量网站进行分类.实际情况是,一个网站可能同时有多个标签,想象一下新浪网,它既是门户站 ...

  2. Flex + Bison: Scanning from memory buffer

    Found from StackOverflow: ========================================================================== ...

  3. windows 多个人同时远程同一台电脑

    windows  多个人同时远程同一台电脑 第一步:(内外远程) 参考内网多个人同时远程一台电脑: http://www.cnblogs.com/zlp520/p/7688984.html 第二步:( ...

  4. c# 委托与事件的区别

    委托与事件的区别 委托和事件没有可比性,因为委托是数据类型,事件是对象(可以理解为对委托变量的封装.),下面说的是委托的对象(用委托方式实现的事件)和(标准的event方式实现)事件的区别.事件的内部 ...

  5. [Perl][文件操作]判断文件是否为符号链接(Unicode路径)

    Win32API::File 判断文件/文件夹是否为符号链接 Win32::Unicode 好像无法做这方面的判断,只能判断是否为目录.文件.文件是否存在. Win32API::File 则支持 Ge ...

  6. Ubuntu16.04 JAVA配置!

    下面是转发的文章,写得不错,不过有些地方需要注意: 1,以root身份登入,安装和配置JDK,这样JDK是全局的,其他用户也可以使用! 2,下面文章中的JDK版本应该比我们目前能够下载的要旧,我们把下 ...

  7. lua 5.3 英文手册 自己收集整理版

    /* ** state manipulation */ LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);//创建lua虚拟机 LUA ...

  8. 微信小程序遇到的问题与解决

    1.微信开发工具报错 400 (Bad Request) 解决方法: 注:因为开发工具升级 content-type的写法变了 如下代码: header:{     "Content-Typ ...

  9. [Maven实战-许晓斌]-[第二章]-2.7-2.8 Mave安装的最优建议和安装小结

    2.7

  10. Python多继承的C3算法

    C3算法 一.知识点补充: 拓扑排序:在图论中,拓扑排序(Topological Sorting) 是一个 有向无环图(DAG,Directed Acyclic Graph) 的所有顶点的线性序列.且 ...