Ehcache缓存框架详解

一、前言

ehcache是一个比较成熟的java缓存框架,它提供了用内存,磁盘文件存储,以及分布式存储方式等多种灵活的cache管理方案。ehcache最早从hibernate发展而来。由于3.x的版本和2.x的版本API差异比较大。这里直接学习最新版本的了,但是最后整合spring的时候还是有2.x。

二、安装

由于我的项目是使用maven管理的,因此只要在pom文件中添加如下代码即可。

<dependency>
    <groupId>javax.cache</groupId>
    <artifactId>cache-api</artifactId>
    <version>1.0.0</version>
</dependency>
<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.3.1</version>
</dependency>

好像ehcache还要依赖上面的那个Cache,因此最好两个多加上。

三、使用

1、快速入门__JAVA实现

CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
    .withCache("preConfigured",
        CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)))
    .build();
cacheManager.init(); 

Cache<Long, String> preConfigured =
    cacheManager.getCache("preConfigured", Long.class, String.class); 

Cache<Long, String> myCache = cacheManager.createCache("myCache",
    CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)));

myCache.put(1L, "da one!");
String value = myCache.get(1L); 

cacheManager.removeCache("preConfigured"); 

cacheManager.close(); 

这里使用的官网的例子。

  • CacheManagerBuilder.newCacheManagerBuilder():创建缓存构造器的构建者,类似工厂模式,注意,里面的实现不是单例。
  • .withCache() :相当于创建一个自带缓存的CacheManager。
  • build() :这个方法就是创建CacheManager了。
    上面的build方法接受一个boolean参数:当为true时,CacheManager在使用时就不用初始化,否则,就需要CacheManager调用init()进行初始化操作。默认为false。
    
  • cacheManager.getCache():获取缓存
  • cacheManager.createCache():创建缓存。
  • myCache.put(1L, “da one!”):在缓存中添加值

2、快速入门__XML实现

    <cache alias="foo">
        <!-- 缓存键值对的类型 -->
        <key-type>java.lang.String</key-type>
        <value-type>java.lang.String</value-type>
        <!-- 配置缓存 -->
        <expiry>
            <ttl unit="seconds">2</ttl>
        </expiry>
        <resources>
            <!-- 在堆中申请2000个entries -->
            <heap unit="entries">2000</heap>
            <!-- 最大非堆内存 -->
            <offheap unit="MB">500</offheap>
        </resources>

    </cache>
    <!-- 定一个模板 -->
    <cache-template name="myDefaults">
        <key-type>java.lang.Long</key-type>
        <value-type>java.lang.String</value-type>
        <heap unit="entries">200</heap>
    </cache-template>
    <!-- 使用上面的模板 -->
    <cache alias="bar" uses-template="myDefaults">
        <key-type>java.lang.Number</key-type>
    </cache>

    <cache alias="simpleCache" uses-template="myDefaults" />
// 测试xml
    @Test
    public void test03() {
        URL url = getClass().getResource("/ehcache.xml");
        XmlConfiguration conf = new XmlConfiguration(url);
        CacheManager cacheManager = CacheManagerBuilder.newCacheManager(conf);
        cacheManager.init();
        Cache<String, String> cache = cacheManager.getCache("foo", String.class, String.class);
        cache.put("key", "value");
        try {
            Thread.sleep(1000); // 测试过期时间
            String value = cache.get("key");
            System.out.println("result:" + value);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

上面即演示了xml实现缓存,注释都比较清楚了。之所以在java中调用Thread.sleep(1000),就是为了测试在xml中设置过期时间是否有效。

三、磁盘缓存

PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder()
                .with(CacheManagerBuilder.persistence(new File("myData")))
                .withCache("threeTieredCache",
                        CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
                                ResourcePoolsBuilder.newResourcePoolsBuilder().heap(10, EntryUnit.ENTRIES)
                                        .offheap(1, MemoryUnit.MB).disk(20, MemoryUnit.MB, true)))
                .build(true);

        Cache<Long, String> threeTieredCache = persistentCacheManager.getCache("threeTieredCache", Long.class,
                String.class);
        threeTieredCache.put(1L, "stillAvailableAfterRestart");

        persistentCacheManager.close();

上面代码即会在当前项目的同级目录下创建一个mydata目录。

四、Spring和Ehcache整合

Spring本身并没有提供缓存的功能,但是却对市面上好多缓存框架提供了支持,即也支持Ehcache。由于Spring4好像对ehcache3.x不是太支持,因此这里选用2.x。

ehcache.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <!-- 指定一个文件目录,当EhCache把数据写到硬盘上时,将把数据写到这个文件目录下 -->
    <diskStore path="java.io.tmpdir" />

    <!-- 设定缓存的默认数据过期策略 -->
    <defaultCache maxElementsInMemory="10000" eternal="false"
        overflowToDisk="true" timeToIdleSeconds="10" timeToLiveSeconds="20"
        diskPersistent="false" diskExpiryThreadIntervalSeconds="120" />
    <!--
        name:缓存名称

        maxElementsInMemory:内存中最大缓存对象数

        maxElementsOnDisk:硬盘中最大缓存对象数,若是0表示无穷大

        eternal:true表示对象永不过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds属性,默认为false

        overflowToDisk:true表示当内存缓存的对象数目达到了

        maxElementsInMemory界限后,会把溢出的对象写到硬盘缓存中。注意:如果缓存的对象要写入到硬盘中的话,则该对象必须实现了Serializable接口才行。

        diskSpoolBufferSizeMB:磁盘缓存区大小,默认为30MB。每个Cache都应该有自己的一个缓存区。

        diskPersistent:是否缓存虚拟机重启期数据,是否持久化磁盘缓存,当这个属性的值为true时,系统在初始化时会在磁盘中查找文件名 为cache名称,后缀名为index的文件,这个文件中存放了已经持久化在磁盘中的cache的index,找到后会把cache加载到内存,要想把 cache真正持久化到磁盘,写程序时注意执行net.sf.ehcache.Cache.put(Element element)后要调用flush()方法。

        diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认为120秒

        timeToIdleSeconds: 设定允许对象处于空闲状态的最长时间,以秒为单位。当对象自从最近一次被访问后,如果处于空闲状态的时间超过了timeToIdleSeconds属性 值,这个对象就会过期,EHCache将把它从缓存中清空。只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限 期地处于空闲状态

        timeToLiveSeconds:设定对象允许存在于缓存中的最长时间,以秒为单位。当对象自从被存放到缓存中后,如果处于缓存中的时间超过了 timeToLiveSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清除。只有当eternal属性为false,该属性才有 效。如果该属性值为0,则表示对象可以无限期地存在于缓存中。timeToLiveSeconds必须大于timeToIdleSeconds属性,才有 意义

        memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
     -->
    <cache name="cacheTest"
           maxElementsInMemory="1000"
            eternal="false"
        overflowToDisk="true" timeToIdleSeconds="10" timeToLiveSeconds="20" />

</ehcache>

application.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/cache
           http://www.springframework.org/schema/cache/spring-cache-3.1.xsd">

    <!-- 自动扫描注解的bean -->
    <context:component-scan base-package="com.lw.spring.ehcache" />

    <!-- 注解扫描 -->
    <cache:annotation-driven cache-manager="ehCacheCacheManager" />

    <!-- 实例CacheManager -->
    <bean id="ehCacheCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
        <property name="cacheManager" ref="ehcache"></property>
    </bean>

    <!-- 加载ehcache配置文件 -->
    <bean id="ehcache"
        class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
        <property name="configLocation" value="classpath:ehcache.xml"></property>
    </bean>

</beans>

创建一个service接口,并添加实现。

package com.lw.spring.ehcache;

import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class EhcacheServiceImpl implements EhcacheService {

    /**
     * @Cacheable
     * 表明所修饰的方法是可以缓存的:当第一次调用这个方法时,
     * 它的结果会被缓存下来,在缓存的有效时间内。如果每次缓存返回的结果都是一样的,则不会执行方法体的代码
     * 以后访问这个方法都直接返回缓存结果,不再执行方法中的代码段。
     * @CachePut:功能比@Cacheable更强,不仅缓存方法结果,还缓存代码段,每次都会执行方法体的内容
     * @CacheEvict:功能和@Cacheable功能相反,@CacheEvict表明所修饰的方法是用来删除失效或无用的缓存数据。
     * @CacheConfig:与前面的缓存注解不同,这是一个类级别的注解。如果类的所有操作都是缓存操作,你可以使用@CacheConfig来指定类,省去一些配置。
     * condition:缓存的条件,可以为null,使用spel编写,只有返回true的情况下才进行缓存
     * 这个方法会以key中的值作为缓存中的key,返回结果作为缓存中的值进行缓存
     */
    @CachePut(value = "cacheTest", key = "#param",condition="1<2")
    public String getTime(String param) {
        System.out.println("getTime方法调用了...");
        Long time = System.currentTimeMillis();
        return time.toString();
    }
}

测试:

package com.lw.spring.ehcache;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;

@ContextConfiguration(locations={"classpath:application.xml"})
public class EhcacheTest  extends AbstractJUnit4SpringContextTests{

    @Autowired
    private EhcacheService ehcacheService;

    @Test
    public void getTimestampTest() throws InterruptedException{
        System.out.println("第一次调用:" + ehcacheService.getTime("param"));

        System.out.println("调用:" + ehcacheService.getTime("param"));

        System.out.println("调用:" + ehcacheService.getTime("param"));

        System.out.println("调用:" + ehcacheService.getTime("param"));

        System.out.println("调用:" + ehcacheService.getTime("param"));

        System.out.println("调用:" + ehcacheService.getTime("param"));

        System.out.println("调用:" + ehcacheService.getTime("param"));
        Thread.sleep(11000);// 10s之后缓存消失
        System.out.println("再过11秒之后调用:" + ehcacheService.getTime("param"));
    }
}

上面就完成了Spring和ehcache的结合了。其实主要就是ehcache的核心类交给了Spring。上面还有几个注解,注释里也解释了。

时间: 2024-12-20 16:27:34

Ehcache缓存框架详解的相关文章

Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解

本篇文章继续为大家介绍Universal-Image-Loader这个开源的图片加载框架,介绍的是图片缓存策略方面的,如果大家对这个开源框架的使用还不了解,大家可以看看我之前写的一篇文章Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用,我们一般去加载大量的图片的时候,都会做缓存策略,缓存又分为内存缓存和硬盘缓存,我之前也写了几篇异步加载大量图片的文章,使用的内存缓存是LruCache这个类,LRU是Least Recently Used 近

hadoop 学习笔记:mapreduce框架详解

hadoop 学习笔记:mapreduce框架详解 开始聊mapreduce,mapreduce是hadoop的计算框架,我 学hadoop是从hive开始入手,再到hdfs,当我学习hdfs时候,就感觉到hdfs和mapreduce关系的紧密.这个可能是我做技术研究的 思路有关,我开始学习某一套技术总是想着这套技术到底能干什么,只有当我真正理解了这套技术解决了什么问题时候,我后续的学习就能逐步的加快,而学习 hdfs时候我就发现,要理解hadoop框架的意义,hdfs和mapreduce是密不

iOS 开发之照片框架详解之二 —— PhotoKit 详解(下)

这里接着前文<iOS 开发之照片框架详解之二 —— PhotoKit 详解(上)>,主要是干货环节,列举了如何基于 PhotoKit 与 AlAssetLibrary 封装出通用的方法. 三. 常用方法的封装 虽然 PhotoKit 的功能强大很多,但基于兼容 iOS 8.0 以下版本的考虑,暂时可能仍无法抛弃 ALAssetLibrary,这时候一个比较好的方案是基于 ALAssetLibrary 和 PhotoKit 封装出一系列模拟系统 Asset 类的自定义类,然后在其中封装好兼容 A

iOS 开发之照片框架详解之二 —— PhotoKit 详解(上)

一. 概况 本文接着 iOS 开发之照片框架详解,侧重介绍在前文中简单介绍过的 PhotoKit 及其与 ALAssetLibrary 的差异,以及如何基于 PhotoKit 与 AlAssetLibrary 封装出通用的方法. 这里引用一下前文中对 PhotoKit 基本构成的介绍: PHAsset: 代表照片库中的一个资源,跟 ALAsset 类似,通过 PHAsset 可以获取和保存资源 PHFetchOptions: 获取资源时的参数,可以传 nil,即使用系统默认值 PHAssetCo

Hibernate 所有缓存机制详解

Hibernate 所有缓存机制详解 hibernate提供的一级缓存 hibernate是一个线程对应一个session,一个线程可以看成一个用户.也就是说session级缓存(一级缓存)只能给一个线程用,别的线程用不了,一级缓存就是和线程绑定了. hibernate一级缓存生命周期很短,和session生命周期一样,一级缓存也称session级的缓存或事务级缓存.如果tb事务提交或回滚了,我们称session就关闭了,生命周期结束了. 缓存和连接池的区别:缓存和池都是放在内存里,实现是一样的

(转) shiro权限框架详解06-shiro与web项目整合(上)

http://blog.csdn.net/facekbook/article/details/54947730 shiro和web项目整合,实现类似真实项目的应用 本文中使用的项目架构是springMVC+mybatis,所以我们是基于搭建好的项目进行改造的. 将shiro整合到web应用中 登录 退出 认证信息在页面展现,也就是显示菜单 shiro的过滤器 将shiro整合到web应用中 数据库脚步 sql脚步放到项目中,项目上传到共享的资源中,文章最后给出共享url. 去除项目中不使用shi

(转) IOS ASI http 框架详解

(转) IOS ASI http 框架详解 ASIHTTPRequest对CFNetwork API进行了封装,并且使用起来非常简单,用Objective-C编写,可以很好的应用在Mac OS X系统和iOS平台的应用程序中.ASIHTTPRequest适用于基本的HTTP请求,和基于REST的服务之间的交互. ASIHTTPRequest功能很强大,主要特色如下: l 通过简单的接口,即可完成向服务端提交数据和从服务端获取数据的工作 l 下载的数据,可存储到内存中或直接存储到磁盘中 l 能上传

《深入理解mybatis原理6》 MyBatis的一级缓存实现详解 及使用注意事项

<深入理解mybatis原理> MyBatis的一级缓存实现详解 及使用注意事项 0.写在前面   MyBatis是一个简单,小巧但功能非常强大的ORM开源框架,它的功能强大也体现在它的缓存机制上.MyBatis提供了一级缓存.二级缓存 这两个缓存机制,能够很好地处理和维护缓存,以提高系统的性能.本文的目的则是向读者详细介绍MyBatis的一级缓存,深入源码,解析MyBatis一级缓存的实现原理,并且针对一级缓存的特点提出了在实际使用过程中应该注意的事项. 读完本文,你将会学到: 1.什么是一

MTK平台LCD驱动框架详解(一)

许多学习嵌入式的进入MTK开发平台,很多东西都会感到很陌生.在MTK平台上你可以简简单单几分钟就点亮一块屏.加上MTK快速开发的节奏,也很少有时间自己整理学习.如果不思进取,不加班加点学习.很容易就慢慢--.这也难怪有些人说MTK造就了一批懒人,毁掉了一批工程师.但其实都是基于linux开发,核心的东西都是一样一样的.我刚入行业,在迷茫之际,自己整理跟踪源码.想慢慢找回自己熟悉的感觉,掌握MTK的整体框架.也希望能给有需要的人带来些帮助.好吧!前话说到这,开始正题. 本文肯定有不少地方会出现错误