Ehcache,一个纯Java的进程内存缓存框架。本地缓存相比较于分布式缓存(例如Redis等)而言,由于避免网络IO通讯的开销故效率非常高。这里就如何在SpringBoot下进行集成、应用来进行介绍
依赖
在POM文件中添加如下依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-cacheartifactId>
dependency>
<dependency>
<groupId>net.sf.ehcachegroupId>
<artifactId>ehcacheartifactId>
<version>2.10.6version>
dependency>
配置
这里我们使用XML配置文件的方式来进行配置。在src/main/resources目录下创建名为ehcache.xml的Ehcache配置文件,示例如下
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"maxBytesLocalHeap="30K">
<diskStore path="user.dir/Ehcache"/>
<defaultCache eternal="false"timeToIdleSeconds="123" timeToLiveSeconds="311"maxBytesLocalHeap="13K" overflowToDisk="false" diskPersistent="false"memoryStoreEvictionPolicy="LRU">
defaultCache>
<cache name="stuInfo" eternal="false"timeToIdleSeconds="0" timeToLiveSeconds="300"maxBytesLocalHeap="12K" overflowToDisk="false" diskPersistent="false"memoryStoreEvictionPolicy="LRU">
cache>
ehcache>
这里就常见的配置项,说明如下
diskStore path
当 内存缓存中的数量超过maxElementsInMemory 且 overflowToDisk为true时 时,会将缓存数据存储到磁盘缓存中。当然被缓存的对象需要实现Serializable序列化接口)。该配置指定磁盘缓存文件的路径。其可选值通常有:
- user.home:用户主目录
- user.dir:用户当前的工作目录
- java.io.tmpdir:默认临时路径
- 自定义绝对路径
对于上述几个变量的具体路径可通过下述方式来了解、确定
public static void main(String[] args) {
System.out.println(": " + System.getProperty("user.home"));
System.out.println(": " + System.getProperty("user.dir"));
System.out.println("" + System.getProperty("java.io.tmpdir"));
}
测试结果如下
defaultCache
默认的缓存配置,其是可选地。该配置将应用于 通过CacheManager.add(String cacheName)以编程方式创建的缓存。如果使用了CacheManager.add(String cacheName)而无该配置将会引起CacheException
name
缓存名称,用于唯一标识缓存
eternal
缓存中的数据是否永久有效。当其为true时,将会忽略timeToIdleSeconds、timeToLiveSeconds配置
timeToIdleSeconds
缓存数据在失效前允许的闲置时间(Unit: second)。若缓存数据超过该时间间隔后未被访问,则该缓存数据即会被从Cache中清除。默认值为0,意为无穷大。显然该配置仅仅在eternal为false时生效
timeToLiveSeconds
缓存数据的生存时间(Unit: second)。默认值为0,意为无穷大。显然该配置仅仅在eternal为false时生效
maxBytesLocalHeap
用于指定CacheManager下所有Cache 或 某个Cache 在内存中缓存数据的容量上限。显然各Cache所使用总内存(12KB+13KB)不可超过CacheManager所指定的总内存容量(30KB)
maxEntriesLocalHeap
其还支持通过对Cache中缓存数据的数量进行限制,即在Cache标签内的maxEntriesLocalHeap属性(例如,maxEntriesLocalHeap="100"),其中0意为无上限。值得注意的是,上述两种限制方式:内存容量(maxBytesLocalHeap)、缓存数量(maxEntriesLocalHeap),只可使用其中一种。即不可同时使用、指定上述两种属性的值
overflowToDisk
内存缓存中缓存数据超过上限(maxElementsInMemory)时,是否使用硬盘保存。值为true时,使用硬盘来保存缓存数据;值为false时,会根据memoryStoreEvictionPolicy配置的淘汰策略来淘汰内存缓存中的数据
diskPersistent
磁盘持久化。当其为true时,在重启虚拟机后会将硬盘缓存加载到内存缓存中
memoryStoreEvictionPolicy
缓存淘汰策略。当内存缓存数据的数量达到上限maxElementsInMemory 且 overflowToDisk为false时,Ehcache即会利用该配置执行相应的淘汰策略。其可选值有:
- FIFO:先进先出策略
- LFU:最近最不常用策略
- LRU:最近最少使用策略
基本操作
在Ehcache中通常有以下几个概念
- CacheManager:缓存管理器,是Ehcache框架的核心类和入口。可通过Ehcache配置文件来获取该类的实例
- Cache:每个CacheManager可以管理若干个Cache
- Element:每个Cache可以管理若干个Element,真正用于存放缓存数据
基本使用方法如下所示
public class TestEhcache {
public static void main(String[] args) {
// 获取缓存管理器
CacheManager manager = CacheManager.newInstance("src/main/resources/ehcache.xml");
// 通过缓存管理器获取Cache
Cache stuInfoCache = manager.getCache("stuInfo");
StuInfo stuInfo1 = new StuInfo(1, "Aaron", 25);
// 构造缓存元素, key: id, value: stuInfo对象
Element element1 = new Element(stuInfo1.getId(), stuInfo1 );
// 放入缓存
stuInfoCache.put(element1);
// 根据key从Cache获取相应的Element
Element element2 = stuInfoCache.get( (Object)stuInfo1.getId() );
// Element的value即为所需的缓存数据
StuInfo stuInfo2 = (StuInfo) element2.getObjectValue();
System.out.println("stuInfo2 : " + stuInfo2);
}
}
/**
* 学生信息
*/
@Data // 生成 get/set 方法
@AllArgsConstructor // 生成全参构造器
@NoArgsConstructor // 生成无参构造器
class StuInfo {
/**
* ID号
*/
private Integer id;
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
}
测试结果如下,符合预期
通过Sping Cache注解操作缓存
Spring中关于缓存的操作,提供了下列注解
- @Cacheable:如果有缓存则不执行方法、直接获取缓存数据; 否则执行方法并设置缓存数据以备下一次访问。适用于读数据的方法
- @CachePut:执行方法,并设置缓存。适用于新增、修改数据的方法
- @CacheEvict:执行方法,并删除缓存。适用于删除数据的方法
使用示例如下所示
public class StuInfoService {
/**
* 缓存名称
*/
private static final String cacheName = "stuInfo";
@Cacheable(value = cacheName, key = "#id")
public StuInfo getStuInfoById(Integer id) {
System.out.println("begin ");
...
System.out.println("end ");
return stuInfo;
}
@CachePut(value = cacheName, key = "#id")
public StuInfo updateStuInfoById(StuInfo stuInfo) {
System.out.println("begin ");
...
System.out.println("end ");
return stuInfo;
}
/**
* 删除指定缓存下的指定key的缓存数据
*/
@CacheEvict(value = cacheName, key = "#id")
public void deleteStuInfoById(Integer id) {
System.out.println("begin ");
...
System.out.println("end ");
}
/**
* 删除指定缓存下的所有缓存数据
*/
@CacheEvict(value = cacheName, allEntries = true)
public void deleteAll() {
System.out.println("begin ");
...
System.out.println("end ");
}
}