• Java Cache 缓存方案详解及代码-Ehcache


    一、Spring缓存概念

    Spring从3.1开始定义了 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口来统一不同的缓存技术; 并支持使用 JCache(JSR-107) 注解简化我们开发。

    常用的缓存实现有 RedisCache 、EhCache、ConcurrentMapCache 、Guava Cache(谷歌)等。

    1、Spring Cache 介绍

    Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单的加一个注解,就能实现缓存功能

    Spring Cache提供了一层抽象,底层可以切换不同的Cache实现,具体是通过CacheManager接口来统一不同的缓存技术

    针对于不同的缓存技术需要实现不同的CacheManager:

    CacheManager

    描述

    EhCacheCacheManager

    使用EhCache作为缓存技术

    GuavaCacheManager

    使用Google的GuavaCache作为缓存技术

    RedisCacheManager

    使用Redis作为缓存技术

    2、Spring Cache 常用注解

    我们来介绍Spring Cache用于缓存的常用的四个注解:

    注解

    说明

    @EnableCaching

    开启缓存注解功能

    @Cacheable

    在方法执行前先查看缓存中是否存有数据,如果有数据直接返回数据;如果没有,调用方法并将返回值存入缓存

    @CachePut

    将方法的返回值放到缓存

    @CacheEvict

    将一条或多条从缓存中删除

    在Spring项目中,使用缓存技术只需要导入相关缓存技术的依赖包,并在启动类上加上@EnableCaching开启缓存支持即可

    二、Ehcache介绍

    EhCache 是一个纯Java的进程内缓存管理框架,属于开源的Java分布式缓存框架,主要用于通用缓存,Java EE和轻量级容器,是从 Hibernate 的缓存开始的。

    目前版本已到了Ehcache 3.10,Ehcache 3引入了以下内容:

    • 改进的 API,利用 Java 泛型并简化缓存交互,

    • 与javax.cache API (JSR-107)完全兼容,

    • 堆下存储功能,包括仅堆下缓存,

    • 开箱即用的Spring Caching和Hibernate集成,这要归功于javax.cache支持

    1、 Ehcache特性:

    1、快速轻量: Ehcache 是最快的 Java 缓存之一,很小的 jar 包

    2、伸缩性:缓存在内存和磁盘存储可以伸缩到数 G

    3、灵活性:Ehcache 1.2 具备对象 API 接口和可序列化 API 接口。

    4、标准支持 Ehcache 提供了对 JSR107 JCACHE API 最完整的实现

    5、可扩展性 监听器可以插件化

    6、应用持久化 在 VM 重启后,持久化到磁盘的存储可以复原数据

    官网:Ehcache

    2、 Ehcache 的加载模块列表

    ehcache-core:API,标准缓存引擎,RMI 复制和 Hibernate 支持

    ehcache:分布式 Ehcache,包括 Ehcache 的核心和 Terracotta 的库

    ehcache-monitor:企业级监控和管理

    ehcache-web:为 Java Servlet Container 提供缓存、gzip 压缩支持的 filters

    ehcache-jcache:JSR107 JCACHE 的实现

    ehcache-jgroupsreplication:使用 JGroup 的复制

    ehcache-jmsreplication:使用 JMS 的复制

    ehcache-openjpa:OpenJPA 插件

    ehcache-server:war 内部署或者单独部署的 RESTful cache server

    ehcache-unlockedreadsview:允许 Terracotta cache 的无锁读

    ehcache-debugger:记录 RMI 分布式调用事件

    Ehcache for Ruby:Jruby and Rails 支持

    3、核心定义

    • cache manager:缓存管理器,以前是只允许单例的,不过现在也可以多实例了

    • cache:缓存管理器内可以放置若干 cache,存放数据的实质,所有 cache 都实现了 Ehcache 接口

    • element:单条缓存数据的组成单位

    • system of record(SOR):可以取到真实数据的组件,可以是真正的业务逻辑、外部接口调用、存放真实数据的数据库等等,缓存就是从 SOR 中读取或者写入到 SOR 中去的

    Ehcache 支持的数据存储包括:

    • 堆上存储 - 利用 Java 的堆上 RAM 内存来存储缓存条目。此层使用与 您的 Java 应用程序,所有这些应用程序都必须由 JVM 垃圾回收器扫描。您的 JVM 堆空间越多 利用,应用程序性能受垃圾回收暂停的影响就越大。这家商店是 速度极快,但通常是您最有限的存储资源。

    • 堆外存储 - 大小仅受可用 RAM 的限制。 不受 Java 垃圾回收 (GC) 的约束。 非常快,但比堆上存储慢,因为在存储和重新访问数据时,必须将数据移入和移出 JVM 堆。

    • 磁盘存储 - 利用磁盘(文件系统)存储缓存条目。 这种类型的存储资源通常非常丰富,但比基于 RAM 的存储慢得多。至于所有使用磁盘的应用程序 存储时,建议使用快速专用的磁盘来优化吞吐量。

    • 群集存储 - 此数据存储是远程服务器上的缓存。 远程服务器可以选择具有故障转移服务器,以提供改进的高可用性。 由于群集存储会因网络延迟以及建立客户端/服务器一致性等因素而带来性能损失, 从本质上讲,此层比本地堆外存储慢。

    三、开发实例:

    引入依赖:

    
    <code class="language-plaintext hljs"> <dependency>
          <groupId>org.ehcache</groupId>
          <artifactId>ehcache</artifactId>
          <version>3.10.0</version>
        </dependency>  </code>

    配置文件:

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <ehcache updateCheck="false" name="defaultCache">
    3. <diskStore path="../temp/bojun/ehcache" />
    4. <!-- 默认缓存配置. -->
    5. <defaultCache maxEntriesLocalHeap="100" eternal="false" timeToIdleSeconds="1800" timeToLiveSeconds="3600"
    6. overflowToDisk="false" maxEntriesLocalDisk="100000" />
    7. <cache name="SystemAuthorizingRealm" maxEntriesLocalHeap="2000"
    8. eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="0"
    9. overflowToDisk="false" statistics="true">
    10. </cache>
    11. <cache name="shiro-activeSessionCache" maxEntriesLocalHeap="2000"
    12. eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="0"
    13. overflowToDisk="false" statistics="true">
    14. </cache>
    15. <!-- 系统缓存 -->
    16. <cache name="sysCache" maxEntriesLocalHeap="100" eternal="false" overflowToDisk="false"/>
    17. <cache name="cmsCache" maxEntriesLocalHeap="3000" eternal="false" overflowToDisk="false"/>
    18. <cache name="captchaCache" maxEntriesLocalHeap="3000" timeToLiveSeconds="300" eternal="false" overflowToDisk="false"/>
    19. <!-- 用户缓存 -->
    20. <cache name="userCache" maxEntriesLocalHeap="100" eternal="false" overflowToDisk="false"/>
    21. <!-- 工作流模块缓存 -->
    22. <cache name="actCache" maxEntriesLocalHeap="100" eternal="false" overflowToDisk="false"/>
    23. <cache name="sys.config" maxEntriesLocalHeap="100" eternal="false" overflowToDisk="false"/>
    24. <!-- 系统活动会话缓存 -->
    25. <cache name="activeSessionsCache" maxEntriesLocalHeap="10000" overflowToDisk="false"
    26. eternal="false" timeToLiveSeconds="0" timeToIdleSeconds="0"
    27. diskPersistent="true" diskExpiryThreadIntervalSeconds="600"/>
    28. </ehcache>

    配置类代码:

    1. @ConditionalOnProperty(name = "spring.cache.type", havingValue = "ehcache")
    2. @Configuration
    3. @EnableCaching//标注启动缓存.
    4. public class CacheConfig {
    5. /**
    6. * @param ehCacheManagerFactoryBean
    7. * @return
    8. */
    9. @Bean
    10. public EhCacheCacheManager ehCacheCacheManager(EhCacheManagerFactoryBean ehCacheManagerFactoryBean){
    11. System.out.println("CacheConfiguration.ehCacheCacheManager()");
    12. return new EhCacheCacheManager(ehCacheManagerFactoryBean.getObject());
    13. }
    14. /*
    15. * 据shared与否的设置,
    16. * Spring分别通过CacheManager.create()
    17. * 或new CacheManager()方式来创建一个ehcache基地.
    18. */
    19. @Bean
    20. public EhCacheManagerFactoryBean ehCacheManagerFactoryBean(){
    21. System.out.println("CacheConfiguration.ehCacheManagerFactoryBean()");
    22. EhCacheManagerFactoryBean cacheManagerFactoryBean = new EhCacheManagerFactoryBean ();
    23. cacheManagerFactoryBean.setShared(true);
    24. return cacheManagerFactoryBean;
    25. }
    26. }

    工具类:

    1. public class CacheUtils {
    2. private static CacheManager cacheManager = SpringContextHolder.getBean(CacheManager.class);
    3. private static final String SYS_CACHE = "sysCache";
    4. /**
    5. * 获取SYS_CACHE缓存
    6. *
    7. * @param key
    8. * @return
    9. */
    10. public static Object get(String key) {
    11. return get(SYS_CACHE, key);
    12. }
    13. /**
    14. * 获取SYS_CACHE缓存
    15. *
    16. * @param key
    17. * @param defaultValue
    18. * @return
    19. */
    20. public static Object get(String key, Object defaultValue) {
    21. Object value = get(key);
    22. return value != null ? value : defaultValue;
    23. }
    24. /**
    25. * 写入SYS_CACHE缓存
    26. *
    27. * @param key
    28. * @return
    29. */
    30. public static void put(String key, Object value) {
    31. put(SYS_CACHE, key, value);
    32. }
    33. /**
    34. * 从SYS_CACHE缓存中移除
    35. *
    36. * @param key
    37. * @return
    38. */
    39. public static void remove(String key) {
    40. remove(SYS_CACHE, key);
    41. }
    42. /**
    43. * 获取缓存
    44. *
    45. * @param cacheName
    46. * @param key
    47. * @return
    48. */
    49. public static Object get(String cacheName, String key) {
    50. if( getCache(cacheName).get(key) == null){
    51. return null;
    52. }else {
    53. return getCache(cacheName).get(key).get();
    54. }
    55. }
    56. /**
    57. * 获取缓存
    58. *
    59. * @param cacheName
    60. * @param key
    61. * @param defaultValue
    62. * @return
    63. */
    64. public static Object get(String cacheName, String key, Object defaultValue) {
    65. Object value = get(cacheName, key);
    66. return value != null ? value : defaultValue;
    67. }
    68. /**
    69. * 写入缓存
    70. *
    71. * @param cacheName
    72. * @param key
    73. * @param value
    74. */
    75. public static void put(String cacheName, String key, Object value) {
    76. getCache(cacheName).put(key, value);
    77. }
    78. /**
    79. * 从缓存中移除
    80. *
    81. * @param cacheName
    82. * @param key
    83. */
    84. public static void remove(String cacheName, String key) {
    85. getCache(cacheName).evict(key);
    86. }
    87. /**
    88. * 获得一个Cache,没有则显示日志。
    89. *
    90. * @param cacheName
    91. * @return
    92. */
    93. private static Cache getCache(String cacheName) {
    94. Cache cache = cacheManager.getCache(cacheName);
    95. if (cache == null) {
    96. throw new RuntimeException("当前系统中没有定义“" + cacheName + "”这个缓存。");
    97. }
    98. return cache;
    99. }
    100. }

    测试代码:

    1. @Cacheable(key="'user_'+#id",value="userCache")
    2. public User getUserById(String id)
    3. {
    4. return userDao.findById(id);
    5. }

    这是一个cache框架,可以根据需要引入不同的cache实现方案

  • 相关阅读:
    0x00 Spring Boot 3入门学习教程大纲
    10种流行的机器学习算法进行泰坦尼克幸存者分析
    【机器学习】基于多元时间序列对高考预测分析案例
    [新增EA028高压注射器]24套UML+EA和StarUML的建模示范视频-全程字幕(2022.7.4更新)
    33.反射
    如何上传一个已有的Android项目到Gerrit
    腾讯云精彩亮相 2023 长沙·中国 1024 程序员节,共创数智未来!
    opencv入门笔记(一)
    CVE-2020-17530 Struts2-061远程代码执行漏洞
    自学Python只看这个够不够........?
  • 原文地址:https://blog.csdn.net/leesinbad/article/details/128548271