当前位置: 首页 > article >正文

在springboot3.x中使用Ehcache3.x

在springboot3.x中使用Ehcache3.x

Ehcache是一个纯Java的进程内缓存框架,它具有快速、精干等特点,被广泛应用于提升应用性能和减少与后端数据库的交互次数。

主要功能和特点

内存和磁盘存储:Ehcache支持内存和磁盘两种存储方式,当内存缓存达到上限时,可以将数据溢出到磁盘上,从而避免数据丢失。

多种缓存策略:提供了基于时间、基于访问和基于大小的多种缓存失效策略,以及LRU(最近最少使用)、LFU(最少使用)和FIFO(先进先出)等缓存驱逐策略。

持久化缓存:支持将数据持久化到磁盘或其他数据源,以确保应用程序重启后能够从持久化存储中恢复数据。

丰富的API和工具类:提供了易于使用的API和工具类,方便完成缓存的读写和管理。

与多种框架和技术集成:如Spring、Hibernate、MyBatis等,使得用户可以更加便捷地使用Ehcache。

架构和原理

CacheManager缓存管理器,是Ehcache的核心组件之一,用于管理缓存实例。它可以从配置文件中加载缓存配置,创建和管理多个缓存实例。

Cache缓存是实际存储数据的容器,每个缓存实例都有唯一的名称,并由CacheManager创建和管理。缓存通常使用哈希表作为底层数据结构,以实现快速查找缓存项。

缓存项(Cache Entry):缓存中的数据单元,每个缓存项通常包含一个键和一个值,键用于唯一标识缓存项,值是实际的数据。

LRU算法:管理缓存项的访问顺序,确保最近使用的数据项保持在缓存的前部,而最不常使用的数据项位于缓存的尾部。

存储方式

堆存储:将缓存数据存储在Java堆内存中,存取速度快,但容量有限。

堆外存储:基于NIO的DirectByteBuffers实现,存储在堆外内存上,不受GC影响,可以保证响应时间的稳定性,但内存分配开销比堆内存大。

磁盘存储:将数据存储在磁盘上,保障服务重启后内存数据能够重新从磁盘上加载,读取效率最低。

优缺点

优点:

  1. 速度快:采用高效的缓存策略,能够实现快速的数据访问和读写。
  2. 可扩展:支持分布式缓存,可以方便地扩展到多台服务器上。
  3. 可靠性高:内置了多种缓存策略,支持数据持久化和恢复,提供了完善的故障检测和纠正机制。

缺点:

  1. 使用磁盘cache时,非常占用磁盘空间。
  2. 节点重启时,可能存在缓存丢失的问题。
  3. 无法大量存储,受限于JVM。
  4. 集群多节点缓存不一致问题。

Spring Boot中配置和使用

在Spring Boot中使用Ehcache组件通常包括以下几个步骤:

  1. 引入jar包:在Spring Boot项目中引入Ehcache的jar包依赖。
  2. 配置ehcache.xml:在项目resource的目录下新建ehcache.xml配置文件,并加入相关配置,如缓存名称、内存和磁盘存储配置、缓存失效策略等。
  3. 使用Ehcache缓存:通过Spring Boot提供的@Cacheable、@CachePut、@CacheEvict等注解来简化缓存操作。

springboot中可用的注解

在springboot中需要缓存的方法上使用Spring Cache提供的注解,如@Cacheable、@CachePut和@CacheEvict。

Ehcache3.x的配置项

Ehcache3.x的XML配置项提供了灵活的方式来定义缓存的行为和特性。

参数

 

 

 

说明

persistence

直接配置

 

directory

数据存储目录

cache

缓存配置

 

alias

缓存名称

 

key-type

缓存 key 的类型

 

value-type

缓存 value 的类型

 

expiry

缓存过期配置

 

tti

缓存中条目的最大空闲时间

 

ttl

缓存中条目的最大存活时间

 

resources

资源配置

 

heap

堆内存配置

 

unit

大小单位

 

offheap

堆外存配置

 

unit

大小单位

 

disk

磁盘配置

 

persistence

是否持久化

 

unit

大小单位

 

示例配置

以下是一个简单的Ehcache3.x XML配置示例:

xml

<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.x.xsd">

    <!-- 指定缓存目录 -->

    <persistence directory="${java.io.tmpdir}/cache-data"/>

    <!-- 缓存模板 -->

    <cache-template name="default">

        <key-type>java.lang.String</key-type>

        <value-type>java.lang.Object</value-type>

        <expiry>

            <ttl unit="seconds">600</ttl>

        </expiry>

        <resources>

            <heap unit="entries">2000</heap>

            <offheap unit="MB">100</offheap>

        </resources>

    </cache-template>

    <!-- 具体的缓存实例,继承自default模板 -->

    <cache alias="sample" uses-template="default"/>

    <!-- 另一个具体的缓存实例,继承自default模板但覆盖了过期时间 -->

    <cache alias="authority_service" uses-template="default">

        <expiry>

            <ttl unit="hours">1</ttl>

        </expiry>

    </cache>

</config>

在这个示例中,我们定义了一个名为"default"的缓存模板,并设置了键的类型、值的类型、过期策略和资源配置。然后,我们定义了两个具体的缓存实例,它们分别继承了"default"模板,但其中一个覆盖了过期时间。

springboot + ehcache缓存范例

引入依赖

<!-- https://mvnrepository.com/artifact/org.ehcache/ehcache -->

<dependency>

    <groupId>org.ehcache</groupId>

    <artifactId>ehcache</artifactId>

    <version>3.10.8</version>

</dependency>

<!--开启缓存支持-->

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-cache</artifactId>

</dependency>

 <dependency>

      <groupId>javax.cache</groupId>

      <artifactId>cache-api</artifactId>

      <version>1.1.0</version>

  </dependency>

  <dependency>

      <groupId>javax.xml.bind</groupId>

      <artifactId>jaxb-api</artifactId>

      <version>2.3.1</version>

  </dependency>

  <dependency>

      <groupId>org.glassfish.jaxb</groupId>

      <artifactId>jaxb-runtime</artifactId>

      <version>2.3.1</version>

  </dependency>

配置Ehcache

在src/main/resources目录下创建ehcache.xml文件,并配置缓存的相关信息,如缓存名称、内存和磁盘存储配置、缓存失效策略等。

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xmlns="http://www.ehcache.org/v3"

        xmlns:jsr107="http://www.ehcache.org/v3/jsr107"

        xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd

http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">

    <service>

        <jsr107:defaults enable-statistics="true"/>

    </service>

    <cache alias="address" >

        <key-type>java.lang.String</key-type>

        <value-type>java.lang.Object</value-type>

        <expiry>

            <ttl unit="seconds">120</ttl> <!-- 2分钟过期 -->

        </expiry>

        <resources>

            <heap unit="entries">10000</heap>  <!-- 堆内存限制为10000个单位 -->

            <offheap unit="MB">50</offheap>

        </resources>

    </cache>

</config>

application文件中配置

spring:

  cache:

    type: jcache

配置类

在配置类上添加@EnableCaching注解以启用缓存功能:

@EnableCaching

@Configuration

public class CacheManagerConfig {

    @Bean

    JCacheCacheManager ehcacheConfiguration()  {

        // 缓存配置

        try {           

            CachingProvider cachingProvider = Caching.getCachingProvider();           

            URL url = getClass().getResource("/ehcache.xml");

            CacheManager cacheManager = cachingProvider.getCacheManager(

                    url.toURI(),

                    getClass().getClassLoader());

            // jcache

            JCacheCacheManager JCache = new JCacheCacheManager();

            JCache.setCacheManager(cacheManager);

            return JCache;

        }catch (URISyntaxException e) {

            e.printStackTrace();          

        }catch (Exception e) {

            e.printStackTrace();           

        }

                   return null;

    }

}

SpringCache提供了一些实现帮助我们整合 Ehcache 2.x、Caffeine、JSR-107(例如Ehcache3)等框架。SpringCache在JCache包下为JSR-107提供了一个默认实现JCacheCacheManger,这里通过配置类进行了设置。

缓存注解使用

添加service类:

package cn.jet.demoehcache.service;

import cn.jet.demoehcache.entity.Address;

import org.springframework.cache.annotation.Cacheable;

import org.springframework.stereotype.Service;

import java.util.ArrayList;

import java.util.List;

/**

 * @ 基本功能:

 * @ program:demo-Ehcache

 * @ author:Jet

 * @ create:2025-02-14 10:56:06

 **/

@Service

public class AddrService {

    @Cacheable(value = "address")

    public List<Address> getAddressList() {       

        List<Address> addressList = new ArrayList<>();

        for(int i = 0;i<10;i++) {

            Address addr = Address.builder()

                    .id(i+1)

                    .province("省份" + (i+1))

                    .city("城市" + (i+1))

                    .district("县区" + (i+1))

                    .street("街道" + (i+1))

                    .build();

            addressList.add(addr);

        }

        return addressList;

    }   

}

单元测试

@SpringBootTest

public class AddrServiceTest {

    @Autowired

    private AddrService addrService;

    @Test

    public void getAddressListTest() {

        List<Address>addressList1 = addrService.getAddressList();

        System.out.println(addressList1.size());

        List<Address>addressList2 = addrService.getAddressList();

        System.out.println(addressList2.size());

    }  

}

编码使用

添加service类:

Spring本身就定义了缓存接口Cache和管理缓存控制器CacheManager 。注意引入路径。

org.springframework.cache.Cache

org.springframework.cache.CacheManager

添加服务类:

package cn.jet.demoehcache.service;

import cn.jet.demoehcache.entity.Address;

import jakarta.annotation.Resource;

import org.springframework.cache.Cache;

import org.springframework.cache.CacheManager;

import org.springframework.stereotype.Service;

import java.util.ArrayList;

import java.util.List;

/**

 * @ 基本功能:

 * @ program:demo-Ehcache

 * @ author:Jet

 * @ create:2025-02-14 15:24:35

 **/

@Service

public class AddrServiceB {

    @Resource

    CacheManager cacheManager;

    public List<Address> getAddressList() {

        List<Address> addressList = new ArrayList<>();

        //获取缓存对象,"address" 就是 ehcache.xml 中 <cache> 标签的 alias

        Cache cache = cacheManager.getCache("address");

        //获取刚刚存入的值

        Cache.ValueWrapper res = cache.get("addressList");

        //如果没有或者过期就为null

        if (null != res) {

        //这里获取 ehcache.xml 中 <cache> value-type 定义的类型,可以直接强转。

            addressList = (List<Address>) res.get();

        }else {

            for (int i = 0; i < 10; i++) {

                Address addr = Address.builder()

                        .id(i + 1)

                        .province("省份" + (i + 1))

                        .city("城市" + (i + 1))

                        .district("县区" + (i + 1))

                        .street("街道" + (i + 1))

                        .build();

                addressList.add(addr);

            }

            //存入缓存

            cache.put("addressList", addressList);

        }

        return addressList;

    }

}

单元测试

@SpringBootTest

public class AddrServiceBTest {

    @Autowired

    private AddrServiceB addrServiceB;

    @Test

    public void getAddressListTestB() {

        List<Address>addressList1 = addrServiceB.getAddressList();

        System.out.println(addressList1.size());

        List<Address>addressList2 = addrServiceB.getAddressList();

        System.out.println(addressList2.size());

    }

}

清除缓存

清除缓存中指定条目:

try {

    javax.cache.CacheManager cm = ((JCacheCacheManager) cacheManager).getCacheManager();

    javax.cache.Cache<String, Object> cache = cm.getCache("address");

    for (TransmitPointType item : TransmitPointType.values()) {

        cache.remove(item.getCacheKey());

    }

}catch (Exception e) {

    e.printStackTrace();

    throw new ECException(ErrorCode.OPERATE_ERROR.getCode(),e.getMessage());

}

或者:

Cache cache = cacheManager.getCache("address");

cache.evict(Object key)

根据提供的键(key)移除缓存中的一个特定条目。它只会影响指定的缓存项,其他缓存数据不会受到影响。

清除缓存中所有条目:

cacheManager.getCache("aa").clear();

它会移除当前缓存中的所有数据,无论这些数据是否已经过期或是否正在被使用。


http://www.kler.cn/a/592962.html

相关文章:

  • Moonlight-16B-A3B: 变革性的高效大语言模型,凭借Muon优化器打破训练效率极限
  • Fortinet全新下一代防火墙NGFW
  • 若依excel工具类导出excel模板数据带下拉映射
  • 数字化工厂智能制造精益化管理智能工厂数据分析大数据解决方案精品PPT格式
  • 使用 `better-sqlite3` 与 `Express.js` 的最佳实践:是否需要关闭数据库连接?
  • Android手机中各类安全相关知识总结
  • 如何在WordPress中添加下载链接?
  • 【从零开始学习计算机科学】设计模式(二)工厂模式、抽象工厂模式、单例模式、建造者模型、原型模式
  • 基于ssm学科竞赛小程序的设计及实现(源码+lw+部署文档+讲解),源码可白嫖!
  • 数据结构:二叉树(一)·(重点)
  • dockercompose如何重启单个服务和所有服务
  • 【平台优化】大数据集群一个客户端参数引起的任务性能差的问题
  • 【RabbitMQ】RabbitMQ如何保证消息不丢失?
  • 分布式唯一ID生成算法——MongoDB ObjectId 算法
  • 企业微信群聊机器人开发
  • PyQt6加载视频方法示例
  • 单片机学完开发板,如何继续提升自己的技能?
  • 如何在项目中有效管理设计模式的复杂性
  • 【漫话机器学习系列】149.ROC 曲线(Receiver Operating Characteristic Curve)
  • HarmonyOS Next中的弹出框使用