玩转Spring Cache --- 整合进程缓存之王Caffeine Cache和Ehcache3.x【享学Spring】(下)

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 玩转Spring Cache --- 整合进程缓存之王Caffeine Cache和Ehcache3.x【享学Spring】(下)

Ehcache2.x/Ehcache3.x和Spring Cache整合


Ehcache2.xEhcache3.x它最大的一个特点是:3.x不向下兼容2.x。从他俩的GAV坐标也能看出这种差异:


<!-- https://mvnrepository.com/artifact/net.sf.ehcache/ehcache -->
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>2.10.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.ehcache/ehcache -->
<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.7.1</version>
</dependency>


不仅仅GAV变了,包名也都换了,因此是二进制不兼容的,并且3.x和2.x的API都有非常大的差异。


虽然说2.x也还是维护着(毕竟有非常重的历史包袱),但是活跃度已经远不及3.x了,因此我认为拥抱EhCache3.x是大势所趋


这里有意思的是,spring-context-support即使在Spring5后,默认支持的还是EhCache2.x版本(毕竟有很重的历史包袱在呢),并且没有提供3.x版本的支持,这应该也是为何你看到大多数人还只是在使用EhCache2.x的根本原因吧~


Ehcache2.x集成


Ehcache2.x的集成方案几乎同Caffeine,略过。


2.x配置CacheManager的时候,既能全用API方式。当然也能简便的使用ehcache.xml方式,内容形如:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <diskStore path="d:/ehcache/"></diskStore>
    <!-- 默认缓存配置 -->
    <defaultCache maxElementsInMemory="10000" eternal="false"
        timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" />
    <!-- User缓存配置 -->
    <cache name="User" maxElementsInMemory="10000" eternal="false"
        timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true"/>
</ehcache>


关于xml配置文件的更多属性和含义,请参考官方文档的说明

Ehcache3.x集成


Ehcache3.x的社区比EhCache2.x活跃很多,所以拥抱和使用3.x版本似乎是必然的。但是奈何Spring并没有提供内置的CacheManager对3.x提供支持,因此此处我总结继承它的两种方案:


  1. 自己实现CacheManager和Cache等相关规范接口
  2. 使用JSR107的JCache(推荐)


上面截图我们能看到support包里是有对jcache(JSR107)的支持,而切好EhCache3.x它实现了JSR107规范(但没有实现Spring-Cache),为了集成它,我们就用现成的方案:jcache+EhCache3.x来实现对Spring的整合。


第一步:先导包

<!-- JSR107 -->
<dependency>
    <groupId>javax.cache</groupId>
    <artifactId>cache-api</artifactId>
    <version>1.1.1</version>
</dependency>
<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.7.1</version>
</dependency>


先简单看看jcache中JCacheCacheManager的实现:

// @since 3.2
public class JCacheCacheManager extends AbstractTransactionSupportingCacheManager {
  // 可见JCacheCacheManager其实就相当于代理,实际做事的是javax.cache.CacheManager
  @Nullable
  private CacheManager cacheManager;
  private boolean allowNullValues = true;
  public JCacheCacheManager() {
  }
  public JCacheCacheManager(CacheManager cacheManager) {
    this.cacheManager = cacheManager;
  }
  ...
  @Override
  public void afterPropertiesSet() {
    if (getCacheManager() == null) {
      setCacheManager(Caching.getCachingProvider().getCacheManager());
    }
    super.afterPropertiesSet();
  }
  // 它使用的是JCacheCache俩把javax.cache.Cache包装起来  类似于适配的效果
  @Override
  protected Collection<Cache> loadCaches() {
    CacheManager cacheManager = getCacheManager();
    Assert.state(cacheManager != null, "No CacheManager set");
    Collection<Cache> caches = new LinkedHashSet<>();
    for (String cacheName : cacheManager.getCacheNames()) {
      javax.cache.Cache<Object, Object> jcache = cacheManager.getCache(cacheName);
      caches.add(new JCacheCache(jcache, isAllowNullValues()));
    }
    return caches;
  }
  @Override
  protected Cache getMissingCache(String name) {
    CacheManager cacheManager = getCacheManager();
    Assert.state(cacheManager != null, "No CacheManager set");
    // Check the JCache cache again (in case the cache was added at runtime)
    javax.cache.Cache<Object, Object> jcache = cacheManager.getCache(name);
    if (jcache != null) {
      return new JCacheCache(jcache, isAllowNullValues());
    }
    return null;
  }
}


由此可见,实际上JCache就相当于对JSR107做了一层适配,让所有实现了JSR107的缓存方案,都能够用在Spring环境中。


第二步:准备配置(集成)方案,此处给出两种配置方案:

一、使用最容易的JCacheManagerFactoryBean + ehcache.xml的方式:


@EnableCaching
@Configuration
public class CacheConfig extends CachingConfigurerSupport {
    @Bean
    public JCacheManagerFactoryBean cacheManagerFactoryBean() throws IOException {
        JCacheManagerFactoryBean factoryBean = new JCacheManagerFactoryBean();
        // 配置全部写在ehcache.xml这个配置文件内~~~~
        factoryBean.setCacheManagerUri(new ClassPathResource("ehcache.xml").getURI());
        return factoryBean;
    }
    @Bean
    public CacheManager cacheManager(javax.cache.CacheManager cacheManager) {
        // 它必须要包装一个javax.cache.CacheManager,也就是Eh107CacheManager才行
        JCacheCacheManager cacheCacheManager = new JCacheCacheManager();
        // 方式一:使用`JCacheManagerFactoryBean` + xml配置文件的方式
        cacheCacheManager.setCacheManager(cacheManager);
        return cacheCacheManager;
}


ehcache.xml配置文件如下:


<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
        xmlns='http://www.ehcache.org/v3'
        xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.1.xsd">
    <!-- <service>
      <jsr107:defaults>
        <jsr107:cache name="demoCache" template="heap-cache"/>
      </jsr107:defaults>
    </service> -->
    <cache-template name="heap-cache">
        <resources>
            <heap unit="entries">2000</heap>
            <offheap unit="MB">100</offheap>
        </resources>
    </cache-template>
  <!-- 注意:这个cache必须手动配置上,它并不会动态生成 -->
    <cache alias="demoCache" uses-template="heap-cache">
        <expiry>
            <ttl unit="seconds">40</ttl>
        </expiry>
    </cache>
</config>


运行如上单侧,打印结果如下:


模拟去db查询~~~1
----------验证缓存是否生效----------
org.springframework.cache.jcache.JCacheCache@1cc680e
hello cache...


缓存生效(使用的JCacheCache)。


它的基本原理是依赖于Caching.getCachingProvider().getCacheManager()这句代码来生成CacheManager。而EhCache提供了EhcacheCachingProvider实现了CachingProvider接口从而实现了getCacheManager()方法~~~


二、使用org.ehcache.config.CacheConfiguration纯API的方式

关于进程缓存这一块,虽然有好几个产品可供选择,但我推荐使用caffeine。(有的小伙伴为了简单而使用EhCache2.x,我个人是不太推荐这种做法的)


总结


本文介绍了进程缓存之王Caffeine Cache和EhCache。互联网软件神速发展,用户的体验度是判断一个软件好坏的重要原因,所以缓存是必不可少的一个神器。

我曾经的曾经面试过一个一个小伙,让他说说对Spring缓存的理解,它一直描述Redis,从沟通细节中甚至一度让我觉得他眼中的Spring缓存就是指的Redis。希望本文能给小伙伴带来一些帮助,不要有这样的误以为,被同行知道了会很尴尬的~


最后我想说:使用分布式缓存Redis确实能应对非常多的场景(绝大部分都使用Redis这也造成了上面我描述的错觉),但真正意义上的优化、高速缓存等等都是必须对本地缓存有深入了解的~~

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
缓存 NoSQL Java
Spring Boot中的分布式缓存方案
Spring Boot提供了简便的方式来集成和使用分布式缓存。通过Redis和Memcached等缓存方案,可以显著提升应用的性能和扩展性。合理配置和优化缓存策略,可以有效避免常见的缓存问题,保证系统的稳定性和高效运行。
50 3
|
1月前
|
缓存 Java 数据库连接
深入探讨:Spring与MyBatis中的连接池与缓存机制
Spring 与 MyBatis 提供了强大的连接池和缓存机制,通过合理配置和使用这些机制,可以显著提升应用的性能和可扩展性。连接池通过复用数据库连接减少了连接创建和销毁的开销,而 MyBatis 的一级缓存和二级缓存则通过缓存查询结果减少了数据库访问次数。在实际应用中,结合具体的业务需求和系统架构,优化连接池和缓存的配置,是提升系统性能的重要手段。
66 4
|
2月前
|
存储 缓存 Java
Spring缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】使用及注意事项
Spring缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】使用及注意事项
368 2
|
4月前
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
236 24
|
4月前
|
存储 缓存 Java
在Spring Boot中使用缓存的技术解析
通过利用Spring Boot中的缓存支持,开发者可以轻松地实现高效和可扩展的缓存策略,进而提升应用的性能和用户体验。Spring Boot的声明式缓存抽象和对多种缓存技术的支持,使得集成和使用缓存变得前所未有的简单。无论是在开发新应用还是优化现有应用,合理地使用缓存都是提高性能的有效手段。
60 1
|
5月前
|
缓存 Java Spring
Spring缓存实践指南:从入门到精通的全方位攻略!
【8月更文挑战第31天】在现代Web应用开发中,性能优化至关重要。Spring框架提供的缓存机制可以帮助开发者轻松实现数据缓存,提升应用响应速度并减少服务器负载。通过简单的配置和注解,如`@Cacheable`、`@CachePut`和`@CacheEvict`,可以将缓存功能无缝集成到Spring应用中。例如,在配置文件中启用缓存支持并通过`@Cacheable`注解标记方法即可实现缓存。此外,合理设计缓存策略也很重要,需考虑数据变动频率及缓存大小等因素。总之,Spring缓存机制为提升应用性能提供了一种简便快捷的方式。
66 0
|
5月前
|
缓存 NoSQL Java
惊!Spring Boot遇上Redis,竟开启了一场缓存实战的革命!
【8月更文挑战第29天】在互联网时代,数据的高速读写至关重要。Spring Boot凭借简洁高效的特点广受开发者喜爱,而Redis作为高性能内存数据库,在缓存和消息队列领域表现出色。本文通过电商平台商品推荐系统的实战案例,详细介绍如何在Spring Boot项目中整合Redis,提升系统响应速度和用户体验。
81 0
|
3月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
265 2
|
15天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
22天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
76 14