官网对ehcache的描述是:
Ehcache is an open source, standards-based cache that boosts performance, offloads your database, and simplifies scalability. It’s the most widely-used Java-based cache because it’s robust, proven, full-featured, and integrates with other popular libraries and frameworks. Ehcache scales from in-process caching, all the way to mixed in-process/out-of-process deployments with terabyte-sized caches.
Ehcache是一个基于标准的开源缓存,可提高性能,减轻数据库负载并简化可伸缩性。 它是最广泛使用的基于Java的缓存,因为它健壮,可靠,功能齐全并与其他流行的库和框架集成。 Ehcache可以从进程内缓存扩展到具有TB级别缓存的混合进程内/进程外部署。
ehcache特性
- 快速、简单,
纯Java的进程缓存
框架 快速集成
,与springboot、hibernate等框架很友好- 多种
缓存策略
:LRU(最近最少使用算法,默认策略)、FIFO(先进先出)、LFU(最不经常使用策略) - 缓存数据有两级:内存和磁盘,因此无需担心内部不够或者内存爆掉问题
- 缓存数据可以设置在虚拟机重启的过程中写入磁盘
- 具有缓存和缓存管理器的侦听接口
- 支持多缓存管理器实例,以及一个实例的多个缓存区域
ehcache缓存与redis缓存的区别
- ehcache直接在
jvm虚拟机
/java进程
中缓存,可以理解为缓存在内存中,速度快,效率高;但是缓存共享麻烦
,集群分布式应用不方便。可以直接单独使用
,集成于项目内,一般在第三方库中被用到的比较多(如mybatis、shiro等),多用于内部缓存
,或者一般没有微服务的单实例小项目。 - redis是通过
socket
访问到缓存服务,效率比ecache低,比数据库要快很多,处理集群和分布式缓存方便,有成熟的方案。 - 两者可以配合使用,ehcache做项目内部缓存 ,redis做分布式缓存。如果是单个应用或者对缓存访问要求很高的应用,用ehcache。如果是大型系统,存在缓存共享、分布式部署、缓存内容很大的,建议用redis。简单的讲,
小项目/单例/不需节点同步的缓存
>直接ehcache
,大项目/微服务/分布式/性能/管理
>直接reids
。 - 如果强行要搞分布式和缓存共享(不建议),ehcache也有缓存共享方案,不过是通过
RMI
或者Jgroup多播
方式进行广播缓存通知更新,缓存共享复杂,维护不方便;简单的共享可以,但是涉及到缓存恢复,大数据缓存,则不合适。
开源项目
1024程序员节快乐!
以下demo代码已经上传到 spring-cloud-study学习项目 https://github.com/moshowgame/spring-cloud-study 的spring-cloud-study-ehcache
模块
大家可以自由下载、改进、讨论与学习!你的进步也是我的进步,你的意见和留言是我前进的动力!
pom.xml:依赖引入
<dependencies>
<!-- SpringBoot缓存支持启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- Ehcache基础包 -->
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
</dependencies>
Application.java:加@EnableCaching开启缓存
@EnableCaching
为Spring Cache的注解,使用后缓存功能生效,否则无效。
package com.softdev.system.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class EmptyApplication {
public static void main(String[] args) {
SpringApplication.run(EmptyApplication.class,args);
}
}
ehcache.xml:缓存策略配置
新建一个ehcache.xml
与application.yml项目配置文件同级,也就是在src/main/resources/
下。
默认情况下ehcache会自动加载 classpath
根目录下名为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"
updateCheck="false">
<!--
powered by zhengkai.blog.csdn.net
diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
user.home – 用户主目录
user.dir – 用户当前工作目录
java.io.tmpdir – 默认临时文件路径
defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
name:缓存名称。
maxElementsInMemory:缓存最大数目
maxElementsOnDisk:硬盘最大缓存个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
overflowToDisk:是否保存到磁盘,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用算法,默认策略)、FIFO(先进先出)、LFU(最不经常使用策略)。
FIFO,first in first out,先进先出策略。
LFU, Less Frequently Used,最不经常使用策略。缓存的元素有一个hit计数属性,hit值最小的将会被清出缓存。
LRU,Least Recently Used,最近最少使用策略(LRU)是大部分操作系统为最大化页面命中率而广泛采用的一种页面置换算法。该算法的思路是,选择未使用且时间最长的缓存移除掉。
-->
<diskStore path = "Java.io.tmpdir/tmp_ehcache"/>
<defaultCache
eternal="false"
maxElementsInMemory="10000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="259200"
memoryStoreEvictionPolicy="LRU"/>
<cache
name="zhengkai.blog.csdn.net"
eternal="false"
maxElementsInMemory="10000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
参数详解:
diskStore
:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:user.home
– 用户主目录user.dir
– 用户当前工作目录java.io.tmpdir
– 默认临时文件路径-defaultCache
:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。name
:缓存名称。maxElementsInMemory
:缓存最大数目maxElementsOnDisk
:硬盘最大缓存个数。eternal
:对象是否永久有效,一但设置了,timeout将不起作用。overflowToDisk
:当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中- timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
- timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
- diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
- diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
- diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
- memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
- clearOnFlush:内存数量最大时是否清除。
- memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用算法,默认策略)、FIFO(先进先出)、LFU(最不经常使用策略)。
- FIFO,first in first out,先进先出策略。
- LFU, Less Frequently Used,最不经常使用策略。缓存的元素有一个hit计数属性,hit值最小的将会被清出缓存。
- LRU,Least Recently Used,最近最少使用策略(LRU)是大部分操作系统为最大化页面命中率而广泛采用的一种页面置换算法。该算法的思路是,选择未使用且时间最长的缓存移除掉。
application.yml:设置缓存区名称
这里我设置了两个缓存区,例如我给证书查询系统设置缓存:
- cache-certList , 证书列表 ,用于缓存单个证书的详情,
变动比较多
,一有编辑就更新指定id
的记录。 - cache-certType , 证书分类,用于缓存证书分类,
一般很久才会变
,一有编辑就清空所有缓存记录
重新来过。
server:
port: 9999
servlet:
context-path: /ehcache
spring:
http:
encoding:
force: true
charset: UTF-8
application:
name: spring-cloud-study-ehcache
cache:
cache-names:
- cache-certList
- cache-certType
Entity:定义测试实体
package com.softdev.system.demo.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class Cert implements Serializable {
Integer certId;
String certNumber;
}
@Data
public class CertType implements Serializable {
Integer typeId;
String typeName;
String certNumberPrefix;
public CertType(Integer typeId, String typeName, String certNumberPrefix) {
this.typeId = typeId;
this.typeName = typeName;
this.certNumberPrefix = certNumberPrefix;
}
}
Controller:进行缓存
这里用 Controlle
层做缓存,但是实际上建议在Service
或者Repository
/ Mapper
层做缓存,也可以设置一个CacheUtil来设置缓存的id等,然后再设置一个CacheService来设置一些全局缓存。
无论你在哪一层,只要加上注释,马上成!
@Cacheable(value = "cache-certList", key = "#cert.certId")
保存指定的id到缓存。@CacheEvict(value = "cache-certList", key = "#cert.certId")
使指定id的缓存失效。@CacheEvict(value = "cache-certType" , allEntries=true)
使所有缓存都失效,清空该缓存区/组。
package com.softdev.system.demo.controller;
import com.alibaba.fastjson.JSON;
import com.softdev.system.demo.entity.Cert;
import com.softdev.system.demo.entity.CertType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
/**
* EhCache缓存控制器demo
* @author zhengkai.blog.csdn.net
* */
@Slf4j
@RestController
public class DemoController {
@GetMapping("")
public ResponseEntity<String> index(){
return ResponseEntity.ok("请求成功");
}
@RequestMapping("cert/save")
@CacheEvict(value = "cache-certList", key = "#cert.certId")
public Cert save(Cert cert){
log.info("保存cert到数据库:"+ JSON.toJSONString(cert));
return cert;
}
@Cacheable(value = "cache-certList", key = "#cert.certId")
@RequestMapping("cert/find")
public Cert find(Cert cert){
log.info("从数据库中读取cert:"+ JSON.toJSONString(cert));
return cert;
}
@RequestMapping("type/all")
@CacheEvict(value = "cache-certType")
public List<CertType> getType(){
List<CertType> list = new ArrayList<>();
list.add(new CertType(1,"个人证书","csdn-person"));
list.add(new CertType(2,"企业证书","csdn-enterprise"));
list.add(new CertType(3,"云证书","csdn-cloud"));
log.info("从数据库中读取typeList:"+ JSON.toJSONString(list));
return list;
}
@CacheEvict(value = "cache-certType" , allEntries=true)
@RequestMapping("type/clean")
public List<CertType> clean(){
log.info("清理所有typeList缓存");
return null;
}
}
请求URL :开始缓存,校验缓存
-
先查询数据
http://localhost:9999/ehcache/cert/find?certId=1&certNumber=111111
,首次调用控制台会输出从数据库中读取cert:{"certId":1,"certNumber":"111111"}
(因为我们没有数据库,这里模拟从数据库中读取数据出来的感觉)
-
继续查看证书,
连续调用多次
,看控制台输出,没有新的日志生成,代表成功http://localhost:9999/ehcache/cert/find?id=1
-
尝试能否修改缓存中的信息,不可能的,修改失败
-
save接口修改缓存
http://localhost:9999/ehcache/cert/save?certId=1&certNumber=3333
(save方法会让缓存失效,重新查询则会重新获取并缓存)
-
再次进行缓存
http://localhost:9999/ehcache/cert/find?certId=1&certNumber=3333
-
再次验证缓存
http://localhost:9999/ehcache/cert/find?certId=1
@Cacheable:使用缓存
@Cacheable可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略,这个稍后会进行说明。需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的。
@Cacheable
一般可以指定三个属性,value
、key
和condition
。
value属性指定Cache名称
value属性是必须指定的,其表示当前方法的返回值是会被缓存在哪个Cache上的,对应Cache的名称。其可以是一个Cache也可以是多个Cache,当需要指定多个Cache时其是一个数组。
@Cacheable("cache1")//Cache是发生在cache1上的
public User find(Integer id) {
returnnull;
}
@Cacheable({"cache1", "cache2"})//Cache是发生在cache1和cache2上的
public User find(Integer id) {
returnnull;
}
使用key属性自定义key
key属性是用来指定Spring缓存方法的返回结果时对应的key的。该属性支持SpringEL表达式。当我们没有指定该属性时,Spring将使用默认策略生成key。我们这里先来看看自定义策略,至于默认策略会在后文单独介绍。
自定义策略是指我们可以通过Spring的EL表达式来指定我们的key。这里的EL表达式可以使用方法参数及它们对应的属性。使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。下面是几个使用参数作为key的示例。
@Cacheable(value="users", key="#id")
public User find(Integer id) {
return new User(1);
}
@Cacheable(value="users", key="#p0")
public User find(Integer id) {
return new User(1);
}
@Cacheable(value="users", key="#user.id")
public User find(User user) {
return user;
}
@Cacheable(value="users", key="#p0.id")
public User find(User user) {
return user;
}
Condition属性指定发生的条件
有的时候我们可能并不希望缓存一个方法所有的返回结果。通过condition属性可以实现这一功能。condition属性默认为空,表示将缓存所有的调用情形。其值是通过SpringEL表达式来指定的,当为true时表示进行缓存处理;当为false时表示不进行缓存处理,即每次调用该方法时该方法都会执行一次。如下示例表示只有当user的id为偶数时才会进行缓存。
@Cacheable(value={"users"}, key="#user.id", condition="#user.id%2==0")
public User find(User user) {
System.out.println("find user by user " + user);
return user;
}
@CachePut:动态缓存
在支持Spring Cache的环境下,对于使用@Cacheable
标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。
@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
@CachePut也可以标注在类上和方法上。使用@CachePut时我们可以指定的属性跟@Cacheable是一样的。
@CachePut("users")//每次都会执行方法,并将结果存入指定的缓存中
public User find(Integer id) {
returnnull;
}
@CacheEvict:清除缓存
@CacheEvict
是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。@CacheEvict可以指定的属性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的语义与@Cacheable对应的属性类似。即value表示清除操作是发生在哪些Cache上的(对应Cache的名称);key表示需要清除的是哪个key,如未指定则会使用默认策略生成的key;condition表示清除操作发生的条件。下面我们来介绍一下新出现的两个属性allEntries和beforeInvocation。
allEntries属性
allEntries是boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。当指定了allEntries为true时,Spring Cache将忽略指定的key。有的时候我们需要Cache一下清除所有的元素,这比一个一个清除元素更有效率。
@CacheEvict(value="users", allEntries=true)
public void delete(Integer id) {
System.out.println("delete user by id: " + id);
}
beforeInvocation属性
清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用beforeInvocation可以改变触发清除操作的时间,当我们指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素。
@CacheEvict(value="users", beforeInvocation=true)
public void delete(Integer id) {
System.out.println("delete user by id: " + id);
}
Ehcache的类层次模型
Ehcache的类层次模型主要为三层,最上层的是CacheManager
,它是操作Ehcache的入口。我们可以通过CacheManager.getInstance()获得一个单个的CacheManager,或者通过CacheManager的构造函数创建一个新的CacheManager.每个CacheManager都管理着多个Cache。而每个Cache都以一种类Hash的方式,关联着多个Element。而Element则是我们用于存放要缓存内容的地方。
Ehcache的刷新策略
ehcache的刷新策略是当缓存在放入的时候记录一个放入时间,它是用Lazy Evict的方式,在取的时候同设置的TTL比较 。
MemoryStore回收策略
MemoryStore支持三种策略:LRU、LFU、FIFO。
-LRU:最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清除缓存。
-
LFU:最少被使用,缓存的元素有一个hit属性,hit值最小的将会被清除缓存。
-
FIFO:先进先出。
EventHandler事件处理
可以为CacheManager添加事件监听,当对CacheManager增删Cache时,事件处理器将会得到通知。要配置事件处理,需要通过ehcache的配置文件来完成。可以为Cache添加事件监听,当对Cache增删Element时,事件处理器将会得到通知。要配置事件处理,需要通过ehcache的配置文件来完成。
开源项目spring-cloud-study
其实应该叫spring-boot-study的,因为很多都是springboot+单个集成。
我不想集成:直接用EHCACHE API
如果两个缓存框架集成,或者因为业务需要只能直接用API,则可以参考以下用法。
Coding with the Ehcache 3 API
:
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.withCache("preConfigured",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.heap(100))
.build())
.build(true);
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(100)).build());
myCache.put(1L, "da one!");
String value = myCache.get(1L);
cacheManager.close();
- 静态方法
org.ehcache.config.builders.CacheManagerBuilder.newCacheManagerBuilder
返回一个新的org.ehcache.config.builders.CacheManagerBuilder
实例。 - 使用构建器来定义别名为
“ preConfigured”
的缓存。在实际的CacheManager实例上调用cacheManager.build()
时,将创建此缓存。第一个String参数是缓存别名
,用于从CacheManager检索缓存。第二个参数org.ehcache.config.CacheConfiguration
用于配置Cache。我们在org.ehcache.config.builders.CacheConfigurationBuilder上使用静态newCacheConfigurationBuilder()
方法来创建默认配置。 - 最后,调用
build()
返回我们可以使用的完全实例化但未初始化的CacheManager。 - 在使用
CacheManager
之前,需要对其进行初始化
,这可以通过2种方式之一进行初始化:在CacheManager实例上调用CacheManager.init()
,或者在boolean参数设置为true的情况下调用CacheManagerBuilder.build(boolean init)
方法。 - 通过将其别名,键类型和值类型传递给CacheManager来检索缓存。例如,要获取在步骤2中声明的缓存,您需要使用其别名=
“ preConfigured”
,keyType = Long.class
和valueType = String.class
。为了确保类型安全,我们要求传递键和值类型。如果这些键和值类型与我们期望的不同,则CacheManager在应用程序生命周期的早期会引发ClassCastException
。这可以防止缓存受到随机类型的污染。 - 可以根据需要使用CacheManager创建新的Cache实例。就像在步骤2中一样,它需要传入别名以及CacheConfiguration。添加的实例化和完全初始化的Cache将通过
CacheManager.getCache
API返回和/或访问。 - 现在可以使用新添加的缓存来存储条目,这些条目由键值对组成,跟Map对象一样。 put方法的第一个参数是键,第二个参数是值。请记住,
键和值类型必须与CacheConfiguration中定义的类型相同
。此外,key必须唯一
,并且仅与一个值相关联。 - 通过调用
cache.get(key)
方法从缓存中检索值。它仅采用一个参数作为键,并返回与该键关联的值。如果没有与该键关联的值,则返回null。 - 我们可以
CacheManager.removeCache(String)
给定的缓存。 CacheManager将不仅删除其对Cache的引用,还将关闭它。缓存释放所有本地保留的瞬时资源(例如内存)。对此缓存的引用将不可用。 - 为了
释放CacheManager
提供给它管理的Cache实例的所有瞬时资源(内存,线程等),您必须调用CacheManager.close()
,后者依次关闭当时已知的所有Cache实例。
我还想要监控缓存:cache-event-listeners
缓存侦听器允许实现者注册将在发生 缓存事件时执行
的 回调方法
。侦听器是在高速缓存
级别注册的,因此仅接收已向其注册的高速缓存的事件。
官方文档也有详细介绍:http://www.ehcache.org/documentation/3.8/cache-event-listeners.html
CacheEventListenerConfigurationBuilder cacheEventListenerConfiguration = CacheEventListenerConfigurationBuilder
.newEventListenerConfiguration(new ListenerObject(), EventType.CREATED, EventType.UPDATED)
.unordered().asynchronous();
final CacheManager manager = CacheManagerBuilder.newCacheManagerBuilder()
.withCache("foo",
CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, String.class, ResourcePoolsBuilder.heap(10))
.withService(cacheEventListenerConfiguration)
).build(true);
final Cache<String, String> cache = manager.getCache("foo", String.class, String.class);
cache.put("Hello", "World");
cache.put("Hello", "Everyone");
cache.remove("Hello");
Listener 参考,也就是new ListenerObject()的参考实现:
public class NotNullCacheEventListener implements CacheEventListener {
public static final CacheEventListener INSTANCE = new NotNullCacheEventListener();
@Override
public void notifyElementRemoved(final Ehcache cache, final Element element) throws CacheException {
}
@Override
public void notifyElementPut(final Ehcache cache, final Element element) throws CacheException {
removeIfNull(cache, element);
}
@Override
public void notifyElementUpdated(final Ehcache cache, final Element element) throws CacheException {
removeIfNull(cache, element);
}
private void removeIfNull(final Ehcache cache, final Element element) {
if (element.getObjectValue() == null) {
cache.remove(element.getKey());
}
}
@Override
public void notifyElementExpired(final Ehcache cache, final Element element) {
}
@Override
public void notifyElementEvicted(final Ehcache cache, final Element element) {
}
@Override
public void notifyRemoveAll(final Ehcache cache) {
}
@Override
public void dispose() {
}
@Override
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("Singleton instance");
}
}