ehcache介绍

一、SpringBoot默认集成CacheManager

Spring声明式缓存:Spring 定义 CacheManager 和 Cache 接口用来统一不同的缓存技术。例如 JCache、 EhCache、 Hazelcast、 Guava、 Redis 等。在使用 Spring 集成 Cache 的时候,我们需要注册实现的 CacheManager 的 Bean。

Spring Boot 为我们自动配置了多个 CacheManager 的实现。

Spring Boot 为我们自动配置了 JcacheCacheConfiguration、 EhCacheCacheConfiguration、HazelcastCacheConfiguration、GuavaCacheConfiguration、RedisCacheConfiguration、SimpleCacheConfiguration 等。

Spring针对不同的缓存技术,需要实现不同的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已经为我们自动配置了EhCache、Collection、Guava、ConcurrentMap等缓存,默认使用SimpleCacheConfiguration,即使用ConcurrentMapCacheManager。

SpringBoot 缓存

在 Spring Boot中,通过@EnableCaching注解自动化配置合适的缓存管理器(CacheManager),Spring Boot根据下面的顺序去侦测缓存提供者:

  • Generic
  • JCache (JSR-107)
  • EhCache 2.x
  • Hazelcast
  • Infinispan
  • Redis
  • Guava
  • Simple

关于 Spring Boot 的缓存机制:
高速缓存抽象不提供实际存储,并且依赖于由org.springframework.cache.Cache和org.springframework.cache.CacheManager接口实现的抽象。 Spring Boot根据实现自动配置合适的CacheManager,只要缓存支持通过@EnableCaching注释启用即可。

 

二、EHCache API的基本用法

EHCache是来自sourceforge(http://ehcache.sourceforge.net/) 的开源项目,也是纯Java实现的简单、快速的Cache组件。EHCache支持内存和磁盘的缓存,支持LRU、LFU和FIFO多种淘汰算法,支持分 布式的Cache,可以作为Hibernate的缓存插件。同时它也能提供基于Filter的Cache,该Filter可以缓存响应的内容并采用 Gzip压缩提高响应速度。

首先介绍CacheManager类。它主要负责读取配置文件,默认读取CLASSPATH下的ehcache.xml,根据配置文件创建并管理Cache对象。

// 使用默认配置文件创建CacheManager
CacheManager manager = CacheManager.create();
// 通过manager可以生成指定名称的Cache对象
Cache cache = cache = manager.getCache("demoCache");
// 使用manager移除指定名称的Cache对象
manager.removeCache("demoCache");

可以通过调用manager.removalAll()来移除所有的Cache。通过调用manager的shutdown()方法可以关闭CacheManager。
有了Cache对象之后就可以进行一些基本的Cache操作,例如:

//往cache中添加元素
Element element = new Element("key", "value");
cache.put(element);
//从cache中取回元素
Element element = cache.get("key");
element.getValue();
//从Cache中移除一个元素
cache.remove("key");

可以直接使用上面的API进行数据对象的缓存,这里需要注意的是对于缓存的对象都是必须可序列化的。在下面的篇幅中笔者还会介绍EHCache和Spring、Hibernate的整合使用。

三、配置文件

配置文件ehcache.xml中命名为demoCache的缓存配置:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ehcache.xsd">
    <!--timeToIdleSeconds 当缓存闲置n秒后销毁 -->
    <!--timeToLiveSeconds 当缓存存活n秒后销毁 -->
    <!-- 缓存配置 
        name:缓存名称。 
        maxElementsInMemory:缓存最大个数。 
        eternal:对象是否永久有效,一但设置了,timeout将不起作用。 
        timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。 
        timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。 
        overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。 diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。 
        maxElementsOnDisk:硬盘最大缓存个数。 
        diskPersistent:设定在虚拟机重启时是否进行磁盘存储,默认为false
        diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。  memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。 
        clearOnFlush:内存数量最大时是否清除。 -->
    <!-- 磁盘缓存位置 -->
    <diskStore path="java.io.tmpdir" />
    <!-- 默认缓存 -->
    <defaultCache 
        maxElementsInMemory="10000" 
        eternal="false"
        timeToIdleSeconds="120" 
        timeToLiveSeconds="120" 
        maxElementsOnDisk="10000000"
        diskExpiryThreadIntervalSeconds="120" 
        memoryStoreEvictionPolicy="LRU">

        <persistence strategy="localTempSwap" />
    </defaultCache>

    <!-- 测试 -->
    <cache name="GoodsType" 
        eternal="false" 
        timeToIdleSeconds="2400"
        timeToLiveSeconds="2400" 
        maxEntriesLocalHeap="10000"
        maxEntriesLocalDisk="10000000" 
        diskExpiryThreadIntervalSeconds="120"
        overflowToDisk="false" 
        memoryStoreEvictionPolicy="LRU">
    </cache>
</ehcache>

各配置参数的含义:

  • diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。
  • defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
  • name:缓存名称。
  • maxElementsInMemory:缓存中允许创建的最大对象数
  • eternal:缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期,timeout参数将不起作用
  • timeToIdleSeconds:缓存数据在失效前允许的闲置时间(钝化时间)单位秒,也就是在一个元素消亡之前,两次访问时间的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是 0 就意味着元素可以停顿无穷长的时间。
  • timeToLiveSeconds:缓存数据的生存时间,也就是一个元素从构建到消亡的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是0就意味着元素可以停顿无穷长的时间。
  • overflowToDisk:内存不足(当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中)时,是否启用磁盘缓存。diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
  • maxElementsOnDisk:硬盘最大缓存个数。
  • diskPersistent:设定在虚拟机重启时是否进行磁盘存储,默认为false
  • diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。 memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是 LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。 
  • clearOnFlush:内存数量最大时是否清除。
  • memoryStoreEvictionPolicy:缓存满了之后的淘汰算法。LRU和FIFO算法这里就不做介绍。LFU算法直接淘汰使用比较少的对象,在内存保留的都是一些经常访问的对象。对于大部分网站项目,该算法比较适用。

如果应用需要配置多个不同命名并采用不同参数的Cache,可以相应修改配置文件,增加需要的Cache配置即可。

四、Springboot整合EhCache

4.1、添加依赖

<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.7.0</version>
</dependency>

 

4.2、配置

4.2.1、xml方式配置

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ehcache.xsd">
    <!-- 磁盘缓存位置 -->
    <diskStore path="java.io.tmpdir" />
    <!-- 默认缓存 -->
    <defaultCache 
        maxElementsInMemory="10000" 
        eternal="false"
        timeToIdleSeconds="120" 
        timeToLiveSeconds="120" 
        maxElementsOnDisk="10000000"
        diskExpiryThreadIntervalSeconds="120" 
        memoryStoreEvictionPolicy="LRU">

        <persistence strategy="localTempSwap" />
    </defaultCache>

    <!-- 测试 -->
    <cache name="GoodsType" 
        eternal="false" 
        timeToIdleSeconds="2400"
        timeToLiveSeconds="2400" 
        maxEntriesLocalHeap="10000"
        maxEntriesLocalDisk="10000000" 
        diskExpiryThreadIntervalSeconds="120"
        overflowToDisk="false" 
        memoryStoreEvictionPolicy="LRU">
    </cache>
</ehcache>

 

对于EhCache的配置文件也可以通过application.yml文件中使用spring.cache.ehcache.config属性来指定,比如:

spring:
  cache:
    ehcache:
      config: classpath:ehcache.xml

 

4.2.2、java config方式

@Configuration
public class EhcacheConfig {
    @Bean("EhcacheManager")
    public CacheManager cacheManager() {
        CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
                .withCache("articles",
                        CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, ArrayList.class,
                                ResourcePoolsBuilder.newResourcePoolsBuilder()
                                        .heap(1, EntryUnit.ENTRIES)
                                        .offheap(2, MemoryUnit.GB)
                                        //.disk(3, MemoryUnit.GB,true)
                        )
                                .build())
                .build(true);
        return cacheManager;
    }
}

 

 

4.3、开启缓存支持

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;

/**
 * 
 * @ClassName: EhCacheConfig
 * @Description:配置缓存
 * @author cheng
 * @date 2017年10月11日 下午1:00:34
 */
@Configuration
@EnableCaching
public class EhCacheConfig {

}

 

4.4、cache使用

一般情况下,我们在Sercive层进行对缓存的操作。

先介绍 Ehcache 在 Spring 中的注解:在支持 Spring Cache 的环境下

@Repository
@CacheConfig(cacheNames = "GoodsType")
public class GoodsTypeDaoImpl {

    @Cacheable
    public String save(String typeId) {
        System.out.println("save()执行了=============");
        return "模拟数据库保存";
    }

    @CachePut
    public String update(String typeId) {
        System.out.println("update()执行了=============");
        return "模拟数据库更新";
    }

    @CacheEvict
    public String delete(String typeId) {
        System.out.println("delete()执行了=============");
        return "模拟数据库删除";
    }

    @Cacheable
    public String select(String typeId) {
        System.out.println("select()执行了=============");
        return "模拟数据库查询";
    }
}


@RunWith(SpringRunner.class)
@SpringBootTest
public class GoodsTypeDaoImplTest {

    @Autowired
    private GoodsTypeDaoImpl typeDao;

    @Test
    public void testSave() {
        String typeId = "type111";
        // 模拟第一次保存
        String returnStr1 = typeDao.save(typeId);
        System.out.println(returnStr1);
        // 模拟第二次保存
        String returnStr2 = typeDao.save(typeId);
        System.out.println(returnStr2);
    }

 

 

 EHCache的监控
对于Cache的使用,除了功能,在实际的系统运营过程中,我们会比较关注每个Cache对象占用的内存大小和Cache 的命中率。有了这些数据,我们就可以对Cache的配置参数和系统的配置参数进行优化,使系统的性能达到最优。EHCache提供了方便的API供我们调 用以获取监控数据,其中主要的方法有:

//得到缓存中的对象数
cache.getSize();
//得到缓存对象占用内存的大小
cache.getMemoryStoreSize();
//得到缓存读取的命中次数
cache.getStatistics().getCacheHits()
//得到缓存读取的错失次数
cache.getStatistics().getCacheMisses()

 分布式缓存
EHCache从1.2版本开始支持分布式缓存。分布式缓存主要解决集群环境中不同的服务器间的数据的同步问题。具体的配置如下:

在配置文件ehcache.xml中加入
<cacheManagerPeerProvider
Factory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1, multicastGroupPort=4446"/>

<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/>

另外,需要在每个cache属性中加入
<cacheEventListenerFactor
y class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
例如:
<cache name="demoCache"
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="true">
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
</cache>

总结
EHCache是一个非常优秀的基于Java的Cache实现。它简单、易用,而且功能齐全,并且非常容易 与Spring、Hibernate等流行的开源框架进行整合。通过使用EHCache可以减少网站项目中数据库服务器的访问压力,提高网站的访问速度, 改善用户的体验。

posted on 2016-01-24 21:18  duanxz  阅读(5145)  评论(0编辑  收藏  举报