1、ehcache简介与HelloWorld

基于ehcache2.10.5 官方文档: http://www.ehcache.org/generated/2.10.4/html/ehc-all/

ehcache简介

ehcache是​基于标准java缓存(JSR-107)的开源缓存,纯用java语言编写的本地缓存框架,具有使用简单、访问快速、代码小巧等特点,专门服务于java应用程序。ehcache出生早、使用广泛,为很多开源框架和应用所使用如Hibernate、mybatis、spring等。

ehcache对比redis

ehcache有好多功能是不如redis的,比如开源的ehcache不支持数据持久化到硬盘和数据的恢复,而且单就缓存服务本身的处理速度上,ehcache也是不如redis的,毕竟一个是用C语言写的,一个是用java写的。但ehcache好就好在足够简单,上手较快,仅几分钟就能使用上缓存,而且ehcache是处于进程内的本地缓存,在数据传输的速度上是要比redis快的。redis是基于socket的网络传输,服务器与redis传递数据大部分时间都花费在网络传输上,要不人家redis总说,俺的性能瓶颈是网络呢!

1、ehcache具有以下特性:

1、数据可以设置过期时间

缓存为了加快读写,数据一般都是放在内存中的,就目前来看,内存条还有没有像硬盘一样便宜和大容量,所以为了节省内存的资源占用,必须要给内存中的数据设置过期时间,使之过期之后自动淘汰掉。ehcache支持给数据设置过期时间,不但可以给cache设置过期时间,基于编程的方式时还能给element设置过期时间。

2、数据支持淘汰策略

内存的容量毕竟是有限的,当内存中的数据量达到一定量时,就要设计一种算法淘汰掉一些旧的数据,好为新的数据腾出地方来。ehcache目前支持三种数据淘汰算法:LRU、LFU和FIFO。

LRU(Least Recently Used,最近最少使用):LRU是默认设置。当将元素放入cache或使用get调用从cache中检索元素时,将更新元素最后使用的时间戳(LastAccessTime),添加时会把最后使用时间最早(LastAccessTime最小)的元素进行驱除。

LFU(Least Frequently Used,频率最少使用):每个元素被get调用时都会更新元素的命中次数(hitCount)。当添加一个新元素时,若达到内存存储的最大限制时,将删除命中次数(hitCount)最小的元素,即“不常用”元素。

FIFO(First In First Out,先进先出):队列的性质。当添加一个新元素时,若达到内存存储的最大限制时,最先放进该cache的元素会最先被删除。

3、提供了条件查询api

ehcache提供了一些查询api,基本可以像查询RDB一样,查询ehcache中的数据,但是速度却比RDB要快的多。

4、支持后写模式

解决了数据库被频繁写入的性能瓶颈,大大提高了数据库写数据的能力。

等等特性,更多请看官方文档:http://www.ehcache.org/generated/2.10.4/html/ehc-all/#page/Ehcache_Documentation_Set%2Fto-ehcache_online_documentation_library.html%23

5、磁盘临时存储

开源版本中,当堆内存的容量不够时,ehcache会将数据临时存储到磁盘中,只在内存中保存一个磁盘的索引。所以理论上ehcache的容量上限跟磁盘容量有直接关系。

2、ehcache的数据存储结构

ehcache的数据存储结构

 

清楚ehcache的存储结构是十分必要的,对接下来使用ehcache将会带来很大的帮助。

ehcache可以创建多个cacheManager,每个cacheManager包含多个cache,每个cache包含多个element。

1、cacheManager:缓存管理器,用来管理和操作cache。可以基于xml文件创建也可以代码中创建,一个ehcache.xml文件代表着一个cacheManager的配置,所以可以创建多个ehcache-xxx.xml,根据这些不同的ehcache-xxx.xml配置文件,创建不同的cacheManager实例。

2、cache:缓存,用来管理和操作里面的element,还可以对里面的element统一设置过期时间和淘汰策略等属性。

3、element:元素,ehcache中最小的结构单元,结构为key-value对,key可以是任意类型,value也可以是任意类型,此外还可以单独对element进行设置过期时间、命中次数、最后一次访问时间戳等操作。

简单来说,一个cacheManager相当于一个Map<Map<String,Object>>结构,一个cache就是一个hashMap,element相当于map里面的一个个的key-value对。

3、ehcache的数据存储位置

ehcache提供了三种存储数据的方式来优先级依次递减:

1、jvm堆内存(默认开启,会被javaGC,总大小取决于java堆内存大小)

当添加的元素超过设置的堆内存最大内存大小时,如果未启用溢出,则将删除现有元素,不会开启数据过期策略。若启用了溢出,则依次存放到下一级缓存位置中,并将检查所有数据是否过期,如果过期,则将其删除;

调整大小:设置内存大小的属性使用Java -Xmx语法(例如:“ 500k”,“ 200m”,“ 2g”)采用整数,最小单位(字节)

maxBytesLocalHeap:设置ehcache占用堆内存的字节数。不能超过jvm堆内存的大小

maxEntriesLocalHeap:设置ehcache在jvm堆内存中能存储entry的最大数量,不能超过Integer.MAX_VALUE的值。(一个entry就是一个element,也就是一个键值对,类似hashMap中的entry)

2、堆外内存(开源版本不支持,我们使用的就是开源版本)

需要使用ehcache的相关产品才支持堆外内存。另外ehcache不支持数据持久化到硬盘和jvm重启后数据恢复到内存,也是需要使用ehcache的相关产品才行,都是钱啊。

调整大小:

maxBytesLocalOffHeap

3、磁盘(默认开启)

值得一提的是,ehcache会在JVM启动时自动从类路径下找ehcache.xml当做配置文件,如果找不到再找ehcache-failsafe.xml这个文件,而ehcache在依赖的根目录下就为我们提供了ehcache-failsafe.xml文件,所以当我们没有在项目中配置ehcache的配置文件时,就默认使用ehcache为我们提供的ehcache-failsafe.xml配置文件,ehcache-failsafe.xml文件默认开启了磁盘临时缓存,存储的位置就是java.io.tmpdir的值。

开启:

使用<persistence strategy="localTempSwap">配合<diskStore path="java.io.tmpdir"/>来开启和设置磁盘缓存目录。使用localTempSwap策略时,可以在Cache或CacheManager级别使用maxEntriesLocalDisk或maxBytesLocalDisk来控制磁盘层的大小。若超过磁盘存储大小限制,ehcache将使用LFU算法来清除磁盘数据,同时删除内存中的数据索引。

关闭磁盘缓存:

若想关闭磁盘存储,注释掉配置文件中的<diskStore/>标签元素即可。

调整大小:

maxBytesLocalDisk:设置ehcache磁盘缓存的最大字节数。

maxEntriesLocalDisk:设置ehcache磁盘缓存中entry的最大数量,不能超过Integer.MAX_VALUE的值

总的来说,

在cacheManager级别只能使用maxBytesLocalHeap和maxBytesLocalDisk来设置总的占用堆内存和磁盘的大小上限,不设置则默认上限为jvm堆内存设置大小和磁盘容量。

在cache级别可以使用这四个属性,来设置当前cache占用的堆内存和磁盘大小,当然多个cache的总大小不能超过cacheManager配置的上限。

maxBytesxxx和maxEntriesxxx不能单独在cacheManager和cache中同时出现,例如cacheManager中配置了maxBytesLocalHeap,cache中要同时配置maxBytesLocalHeap和maxEntriesLocalHeap才行,不然会报属性不兼容的异常。若不知道怎么配,cacheManager和cache中都配置maxBytesLocalxxx就行了,不会出错。

具体分配情况请看官网示例:http://www.ehcache.org/generated/2.10.4/html/ehc-all/#page/Ehcache_Documentation_Set%2Fco-size_sizing_examples.html%23

2、HelloWorld

1、引入ehcache的依赖

        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.10.5</version>
        </dependency>

2、在类路径下放一个文件ehcache.xml,内容大致如下:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         name="cacheManager1"
         maxBytesLocalHeap="200M"
         maxBytesLocalDisk="20G"
        >

    <!-- 当内存中的数据达到设置上限后,磁盘临时缓存位置 -->
    <diskStore path="D:/ehcacheTempData"/>

    <!-- 配置默认的cache。当代码中使用cacheManager.addCache(cacheName);方法时,若该cacheName对应的cache不存在,将默认使用该配置创建该cache。
注意,基于spring缓存注解时,必须要有cache的name与cacheNames属性对应才行,否则会报Cannot find cache name xxx异常-->
    <defaultCache
            maxBytesLocalHeap="100M"
            maxBytesLocalDisk="10G"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
         <!--启用临时磁盘存储内存溢出的数据,数据存储在diskStore标签指定的地方-->
        <persistence strategy="localTempSwap"/>
    </defaultCache>

    <!-- 单独配置一个cache
        name:缓存名称。
        maxBytesLocalHeap:占用堆内存的大小,使用Java -Xmx语法(例如:“ 500k”,“ 200m”,“ 2g”)采用整数。
        maxBytesLocalDisk:占用磁盘的大小,使用Java -Xmx语法(例如:“ 500k”,“ 200m”,“ 2g”)采用整数。
        maxEntriesLocalHeap:堆内存中的最大entry(ehcache中的元素)数量。
        maxEntriesLocalDisk:磁盘中的最大entry(ehcache中的元素)数量。
        eternal:对象是否永久有效,一但设置了,设置的过期时间将失效,但会被淘汰。
        timeToIdleSeconds:设置element在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,表示永久有效。
        timeToLiveSeconds:设置element的存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0,表示永久有效。
        //overflowToDisk:当内存中element数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中(已过期)。
        //diskPersistent:是否缓存虚拟机重启期数据(已过期,开源版本无效)。
        diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
        diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
        memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
     -->
    <cache name="empCache"
           eternal="true"
           timeToIdleSeconds:3600
           timeToLiveSeconds:3600
           maxBytesLocalHeap="50M"
           maxBytesLocalDisk="5G"
           />


</ehcache>

3、代码方式创建和配置CacheManager、Cache和element,以及element的增删改查

/**
 * ehcache缓存的存储结构和元素的增删改查
 * @throws InterruptedException
 */
@Test
public void test01() throws InterruptedException {
    /**
     * 创建cacheManager可以调用CacheManager的静态方法create()或newInstance(),
     * 这俩方法会根据cacheManager的name,检查是否已经创建了同名的cacheManager,若有则返回已有的,否则创建新的cacheManager。
     */

    //使用默认配置文件创建单例的CacheManager,先到类路径下的找ehcache.xml,若没有再找ehcache-failsafe.xml(ehcache的依赖中默认就提供了这个配置文件)
    CacheManager singleTonCacheManager = CacheManager.create();
    //使用指定的配置文件创建新的CacheManager
    CacheManager cacheManager = CacheManager.newInstance(getClass().getClassLoader().getResourceAsStream("ehcache_config.xml"));

    //创建并配置cache,和在ehcache.xml中配置一样
    CacheConfiguration cacheConfiguration = new CacheConfiguration("测试cache1",1000);


    //统一设置cache中元素过期时间
    cacheConfiguration.setTimeToLiveSeconds(60);
    cacheConfiguration.setTimeToIdleSeconds(60);
    /*cacheConfiguration.setMaxEntriesLocalHeap();
    cacheConfiguration.setMaxEntriesLocalDisk();
    cacheConfiguration.setMaxBytesLocalHeap();
    cacheConfiguration.setMaxBytesLocalDisk();*/
    Cache cache = new Cache(cacheConfiguration);

    //先要将创建的cache放到cacheManager中
    cacheManager.addCache(cache);

    //创建一个element元素
    Element element = new Element("key1","value1");
    Element element2 = new Element("key2","value2");
    //1、将该元素放到cache中
    cache.put(element);
    cache.put(element2);

    //获取元素的过期时间
    int timeToLive = element.getTimeToLive();
    //单独设置元素的过期时间
    element.setTimeToLive(100);
    long creationTime = element.getCreationTime();
    long expirationTime = element.getExpirationTime();
    long hitCount = element.getHitCount();
    long version = element.getVersion();
    //timeToLive:60,creationTime:1604556728911,expirationTime:1604556788911,hitCount:0,version:1
    System.out.println("timeToLive:"+timeToLive+",creationTime:"+creationTime+",expirationTime:"+expirationTime+",hitCount:"+hitCount+",version:"+version);

    //获取cache
    Cache cache1 = cacheManager.getCache("测试cache1");
    Element elem1 = cache1.get("key1");
    Element elem2 = cache1.get("key2");
    //获取元素的key和value
    Object key1 = elem1.getObjectKey();
    Object value1 = elem1.getObjectValue();
    //[ name = 测试cache1 status = STATUS_ALIVE eternal = false overflowToDisk = true maxEntriesLocalHeap = 1000 maxEntriesLocalDisk = 0 memoryStoreEvictionPolicy = LRU timeToLiveSeconds = 60 timeToIdleSeconds = 60 persistence = none diskExpiryThreadIntervalSeconds = 120 cacheEventListeners: ; orderedCacheEventListeners:  maxBytesLocalHeap = 0 overflowToOffHeap = false maxBytesLocalOffHeap = 0 maxBytesLocalDisk = 0 pinned = false ]
    System.out.println(cache1);

    //2、获取元素[ key = key1, value=value1, version=1, hitCount=1, CreationTime = 1604555900407, LastAccessTime = 1604555900407 ]
    System.out.println(elem1);
    //[ key = key2, value=value2, version=1, hitCount=1, CreationTime = 1604557473124, LastAccessTime = 1604557473124 ]
    System.out.println(elem2);
    //key1:key1,value1:value1
    System.out.println("key1:"+key1+",value1:"+value1);

    //3、修改元素的值。同hashMap一样,相同key的后者会覆盖前者
    Element element3 = new Element("key2", "value3");
    cache.put(element3);
    //[ key = key2, value=value3, version=1, hitCount=0, CreationTime = 1604557293391, LastAccessTime = 0 ]
    System.out.println(cache1.get("key2"));

    //4、删除元素element2
    boolean remove = cache.remove("key2");
    //删除成功返回true
    System.out.println(remove);
}

好了ehcache的简介与helloWorld到这里就介绍完了。ehcache也算是一个标准的缓存框架,由于是纯java编写,所以java程序员有兴趣的话好好研究一下它的源码,无论是对代码设计还是缓存的设计都是很有帮助的。另外,有没有发现,ehcache这个单词正过来和反过来都是一样的!

 

下一篇:2、ehcache与springBoot整合

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值