一、简介
EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认缓存提供者。其他关于EhCache的特性以及和rides缓存的比较可以去网上搜索一下,这里不作过多的介绍。以下示例是基于Maven构建的案例。
二、单独使用EhCache示例
1、 在pom.xml中引入EhCache依赖
<!-- 缓存组件 -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.2</version>
</dependency>
2、 在src/main/resources/下新建配置文件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">
<!-- 磁盘缓存位置 -->
<diskStore path="java.io.tmpdir/ehcache"/>
<!-- 默认缓存策略 -->
<defaultCache
maxEntriesLocalHeap="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxEntriesLocalDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</defaultCache>
<!-- 自定义缓存策略,可以根据需求配置多个,以下是一部分配置项的含义,
name :
缓存的名称,使用时通过指定名称获得这个缓存策略的Cache对象。
maxElementsInMemory :
内存中允许存储的最大的元素个数,0代表无限个。
eternal :
设置缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期。根据存储数据的不同,例如一些静态不变的数据如省市区等可以设置为永不过时
timeToIdleSeconds :
设置缓存数据在失效前允许闲置的秒数。仅当eternal=false时有效,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds :
缓存数据的生存时间(TTL),也就是从构建到消亡最大的时间间隔,仅当eternal=false时有效,如果该值是0就意味着元素可以停顿无穷长的时间。
overflowToDisk :
内存不足时,是否启用磁盘缓存。
memoryStoreEvictionPolicy :
如果内存中数据超过内存限制,向磁盘缓存时的策略。默认值LRU,可选FIFO、LFU。
FIFO ,first in first out (先进先出)。
LFU , Less Frequently Used (最少使用),意思是一直以来最少被使用的。缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
LRU ,Least Recently Used(最近最少使用),缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。 -->
<cache name="DataConfig"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="60"
timeToLiveSeconds="60"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
3、 缓存应用
public static void main(String[] args) {
// 1. 创建缓存管理器
CacheManager cacheManager = CacheManager.create("src/main/resources/ehcache.xml");
// 2. 获取缓存对象
Cache cache = cacheManager.getCache("DataConfig");
//向管理器中添加default的缓存策略,提示已经存在,但是去获取default的缓存策略却返回为null,这里需要再研究一下
// cacheManager.addCache("default");
// Cache cache1 = cacheManager.getCache("default");
System.out.println(cache.getName());//DataConfig
// 3. 创建元素
Element element = new Element("key1", "value1");
// 4. 将元素添加到缓存
cache.put(element);
// 5. 获取缓存
Element value = cache.get("key1");
System.out.println(value);//[ key = key1, value=value1, version=1, hitCount=1, CreationTime = 1521081095573, LastAccessTime = 1521081095577 ]
System.out.println(value.getObjectValue());//value1
// 6. 删除元素
cache.remove("key1");
System.out.println(cache.getSize());//0
// 7. 刷新缓存
cache.flush();
// 8. 关闭缓存管理器
cacheManager.shutdown();
}
三、Spring+EhCache示例
1、添加pom依赖,在上面示例基础上增加spring的依赖,其中spring-context-support一定不能少,因为后面用到的bean,如org.springframework.cache.ehcache.EhCacheCacheManager都是来自于这个依赖包,如果没加这个依赖,缓存管理器将无法创建,缓存功能将不起作用。
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>4.10</junit.version>
<spring.version>4.2.3.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<!-- springframework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.3</version>
</dependency>
</dependencies>
2、和上面一样要在src/main/resources/下新建配置文件ehcache.xml(这里就不列出来了),这里需要新增一个配置ehcache bean的spring配置spring-ehcache.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-3.2.xsd">
<description>ehcache缓存配置管理文件</description>
<!-- 启用缓存注解开关 -->
<cache:annotation-driven cache-manager="cacheManager"/>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcache"/>
</bean>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"/>
</bean>
</beans>
注意:因为后面我们要将缓存应用到service层上,因此要确保spring扫描service时spring-ehcache.xml中的bean已经扫描到,否则将会出现缓存功能无效的问题,原因是spring-ehcache.xml中的bean没有被创建出来,解决办法有两个:
- 将spring-ehcache.xml中的配置内容加到spring-service.xml中
- 将spring-ehcache.xml引入到spring-service.xml中,这里使用的是这个方法,如下
<!-- spring-service.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 引入spring-ehcache.xml配置 -->
<import resource="spring-ehcache.xml"/>
<context:component-scan base-package="yx.service"></context:component-scan>
</beans>
3、应用缓存
@Service
public class DataConfigServiceImp implements DataConfigService{
@Autowired
public DataConfigDao dao;
@Cacheable(value="DataConfig", key="'one'+#where")
@Override
public List<DataConfig> select(Map<String, String> where) {
System.out.println("select=========");
return dao.select(where);
}
}
注意:@cacheable中的key值不要写固定值,如key=“one”,这样写会出现一个
Property or field ‘one’ cannot be found on object of type
‘org.springframework.cache.interceptor.CacheExpressionRootObject’ - maybe not public?的错误,如果一定要写固定值,可以这么写key=“‘one’”,引号里面再加一个单引号
@Cacheable
表明所修饰的方法是可以缓存的:当第一次调用这个方法时,它的结果会被缓存下来,在缓存的有效时间内,以后访问这个方法都直接返回缓存结果,不再执行方法中的代码段。
@Cacheable 支持的几个参数:
- value:缓存位置名称,不能为空,值为ehcache.xml中声明的cache的name, 指明使用哪一个缓存策略
- key:缓存的key,默认为空,既表示使用方法的参数类型及参数值作为key,支持SpEL,如果要引用参数值使用井号加参数名,如:#userId,
一般来说,我们的更新操作只需要刷新缓存中某一个值,所以定义缓存的key值的方式就很重要,最好是能够唯一,因为这样可以准确的清除掉特定的缓存,而不会影响到其它缓存值 ,本例子中使用字符串one再加查询条件组合成键的名称 - condition:触发条件,只有满足条件的情况才会加入缓存,默认为空,既表示全部都加入缓存,支持SpEL,如:
@Cacheable(value="DataConfig", condition="#where.size() < 2")
public List<DataConfig> select(Map<String, String> where) {
System.out.println("select=========");
return dao.select(where);
}
@CacheEvict
与@Cacheable功能相反,@CacheEvict表明所修饰的方法是用来删除失效或无用的缓存数据。
@CacheEvict 支持如下几个参数:
- value:和@Cacheable一样
- key:和@Cacheable一样
- condition:触发条件,只有满足条件的情况才会清除缓存,写法和@Cacheable一样
- allEntries:true表示清除value中的全部缓存,默认为false
//清除掉DataConfig中某个指定key的缓存
@CacheEvict(value="DataConfig",key="'one' + #where")
public void removeDataConfig(Map<String, String> where) {
System.out.println("remove========="+where);
}
//清除掉DataConfig中全部的缓存
@CacheEvict(value="DataConfig", allEntries=true)
public final void setReservedDataConfig() {
System.out.println("DataConfig removeall");
}