公司在项目中使用的是redis的缓存,但是由于日后会涉及到使用Ehcache,所以在这里事先在自己的工作之余简单的学习了解了一下Ehcache。搭建了一个小demo,在这里向大家讲解一下,加深一下自己的印象。
一、基本介绍
写在前面:我是昨晚知道项目以后会涉及到使用Ehcache,所以趁着工作之余了解了一点浅浅的皮毛,所以以下观点以及实现方式可能有些地方会有问题,欢迎大家给我指出来。
对于Ehcache,网上有很多非常官方的解释,但是看完以后也不知道它到底是个什么东西。总结成一句话:Ehcache 是一个纯Java的进程内缓存框架,具有快速、精干等特点。再说直白一点,就是redis的另外一种存在方式,只不过它并不是一个一直存在的缓存。它随着项目的运行而被加载,随着项目的结束而消亡。
关于它的特点:首先就是它比redis的速度还快,而且实现起来个人觉得比较简单。它缓存数据的时候有两级:内存和磁盘等等
关于Ehcache和redis的对比:
1.Ehcache直接在JVM虚拟机中缓存,速度快,效率高;但是缓存共享麻烦,集群分布式应用不方便。
2.redis是通过socket访问到缓存服务,效率比Ehcache低,比数据库要快很多,处理集群和分布式缓存方便,有成熟的方案。如果是单个应用或者对缓存访问要求很高的应用,用Ehcache。如果是大型系统,存在缓存共享、分布式部署、缓存内容很大的,建议用redis。
3.Ehcache也有缓存共享方案,不过是通过RMI或者Jgroup多播方式进行广播缓存通知更新,缓存共享复杂,维护不方便;简单的共享可以,但是涉及到缓存恢复,大数据缓存,则不合适。
二、项目实例
个人还是用我之前写的那套SpringBoot工程。对于没看过我之前博客的人也没有任何关系,因为我写的这个demo只是记录自己的一次使用。
1.添加依赖
<!--添加ehcache的起步依赖-->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2.在SpringBoot的resource文件夹下,创建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"
updateCheck="false">
<!--指定一个文件目录,当EhCache把数据写到硬盘上时,将把数据写到这个文件目录下
user.home : 用户主目录
user.dir : 用户当前工作目录
java.io.tmpdir : 默认临时文件路径
-->
<diskStore path="java.io.tmpdir/Tmp_EhCache"/>
<!--
name: 缓存名称
eternal: true表示对象永不过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds属性,默认为false
timeToIdleSeconds: 设定允许对象处于空闲状态的最长时间,以秒为单位。当对象自从最近一次被访问后,如果处于空闲状态的时间超过了timeToIdleSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清空。只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限期地处于空闲状态
timeToLiveSeconds: 设定对象允许存在于缓存中的最长时间,以秒为单位。当对象自从被存放到缓存中后,如果处于缓存中的时间超过了 timeToLiveSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清除。只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限期地存在于缓存中。timeToLiveSeconds必须大于timeToIdleSeconds属性,才有意义
maxElementsInMemory: 内存中最大缓存对象数;maxElementsInMemory界限后,会把溢出的对象写到硬盘缓存中。注意:如果缓存的对象要写入到硬盘中的话,则该对象必须实现了Serializable接口才行
memoryStoreEvictionPolicy: 当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)
maxElementsOnDisk: 硬盘中最大缓存对象数,若是0表示无穷大
overflowToDisk: 是否保存到磁盘,当系统宕机时
diskPersistent: 是否缓存虚拟机重启期数据,是否持久化磁盘缓存,当这个属性的值为true时,系统在初始化时会在磁盘中查找文件名为cache名称,后缀名为index的文件,这个文件中存放了已经持久化在磁盘中的cache的index,找到后会把cache加载到内存,要想把cache真正持久化到磁盘,写程序时注意执行net.sf.ehcache.Cache.put(Element element)后要调用flush()方法
diskSpoolBufferSizeMB: 这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
diskExpiryThreadIntervalSeconds: 磁盘失效线程运行时间间隔,默认为120秒
clearOnFlush: 内存数量最大时是否清除
-->
<!--defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则默认缓存策略-->
<defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="true"
diskPersistent="true"
timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU"/>
<cache
name="MyCache"
eternal="false"
maxElementsInMemory="200"
overflowToDisk="false"
diskPersistent="true"
timeToIdleSeconds="0"
timeToLiveSeconds="300"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
里面可以添加若干个<cache …/>标签,每个cache标签对一个cache进行配置。
3.创建一个实体类,用于测试(此处随意创建一个实体类即可)但需要序列化该类
public class Dog implements Serializable {
private String name;
private String color;
private int age;
public Dog() {
}
public Dog(String name, String color, int age) {
super();
this.name = name;
this.color = color;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Dog [name=" + name + ", color=" + color + ", age=" + age + "]";
}
}
4.创建测试类,测试执行Ehcache缓存(create方法传入上边配置的xml文件路径即可)
public class ehcacheTest {
public static void main(String[] args) {
// 1. 创建缓存管理器
CacheManager cacheManager = CacheManager.create("D:\\workspace\\学习空间\\springboot\\src\\main\\resources\\ehcache.xml");
// 2. 获取缓存对象
Cache cache = cacheManager.getCache("MyCache");
// 3. 创建元素
Element element = new Element("key1", "value1");
// 4. 将元素添加到缓存
cache.put(element);
// 5. 获取缓存
Element value1 = cache.get("key1");
System.out.println("获取value: " + value1);
System.out.println("这里打印日志:" + value1.getObjectValue());
// 6. 删除元素
cache.remove("key1");
Dog dog = new Dog("xiaohei", "black", 2);
Element element2 = new Element("dog", dog);
cache.put(element2);
Element value2 = cache.get("dog");
System.out.println("获取value2: " + value2);
Dog dog2 = (Dog) value2.getObjectValue();
System.out.println("打印dog2的对象:" + dog2);
System.out.println("打印cache的size:" + cache.getSize());
// 7. 刷新缓存
cache.flush();
// 8. 关闭缓存管理器
cacheManager.shutdown();
}
}
程序的输出结果为:
获取value: [ key = key1, value=value1, version=1, hitCount=1, CreationTime = 1589525084000, LastAccessTime = 1589525084003 ]
这里打印日志:value1
获取value2: [ key = dog, value=Dog [name=xiaohei, color=black, age=2], version=1, hitCount=1, CreationTime = 1589525084004, LastAccessTime = 1589525084004 ]
打印dog2的对象:Dog [name=xiaohei, color=black, age=2]
打印cache的size:1
至此,将我们需要的数据已经放到了JVM的Ehcache缓存中,可以在SpringBoot中使用@PostConstruct标签将我们需要缓存到Ehcache中的数据先放好,然后在项目中,我们就可以直接通过cache.get(“key”).getObjectValue()方法来获取我们想要的缓存数据。