缓存条目Listener
事件与Listener
JCache中定义了缓存事件的抽象类CacheEntryEvent
public enum EventType {
CREATED, //创建
UPDATED, //更新
REMOVED, //删除
EXPIRED //过期
}
这些事件将被传播到注册在Cache中的CacheEntryListener,这个接口是一个标记接口,与四种事件类型对应的Listener接口都继承了这个接口,分别是CacheEntryCreatedListener、CacheEntryUpdatedListener、CacheEntryRemovedListener和CacheEntryExpiredListener。
Listener的注册
Listener并不一定是在Cache的进程内的,为了避免可能不支持序列化实例的注册,需要使用CacheEntryListenerConfigurations(具体类MutableCacheEntryListenerConfiguration)。
开发可在配置时通过MutableConfiguation.addCacheEntryListenerConfiguration方法增加缓存的Listener配置,或在运行期通过Cache.registerCacheEntryListener方法来注册Listener。Listener可以通过Cache.deregisterCacheEntryListener方法来注销注册。
多个CacheEntryListenerConfiguration可以增加到Configuration中,当缓存初始化时,它使用注册的Factory来创建CacheEntryListener。针对一个缓存可以存在多个Listener对应相同或者不同的EventType。在Listener创建或在其间派发事件,框架并不能保证其先后顺序。
Listener的调用
缓存Listener
●在缓存条目变化后被触发。
●在同步方式,对于一个给定的键,以该事件发生的顺序触发Listener,并阻塞调用线程,直到Listener返回。
●在异步方式,以未定义的顺序遍历多个事件,但针对相同的Key,事件必须按照发生的顺序进行处理。
Listener是观察者模式,同时Listener抛出一个异常并不会导致缓存操作失败。
在一个Listener中修改缓存的值可能会导致死锁,检测和响应死锁是特定于实现的。
缓存实现中已注册的Listener针对每个事件将最多被调用一次。
一个Listener并不一定在事件发生的进程内执行,在分布式环境中Listener可以在任何地方实现。
Listener可以有一个CacheEntryEventFilter,通过CacheEntryListenerConfiguration来配置。
Filter和同样Listener,它并不一定在事件发生的进程内执行。在分布式环境中,Filter可能实现在任何能提供最好性能的节点处。
下表总结了由每个缓存操作调用的Listener操作。条件是在操作前的条目的状态,过期始终是“否”,过期的确切时间基于缓存的特定实现。
| 方法 |
创建 |
过期 |
删除 |
更新 |
| boolean containsKey(K key) |
否 |
否 |
否 |
否 |
| V get(K key) |
是, 如果是通过read-through创建 |
否 |
否 |
否 |
| Map
|
是, 如果是通过read-through创建 |
否 |
否 |
否 |
| V getAndPut(K key, V value) |
是,如果不存在 |
否 |
否 |
是,如果存在 |
| V getAndRemove(K key) |
否 |
否 |
是,如果存在 |
否 |
| V getAndReplace(K key, V value) |
否 |
否 |
否 |
是,如果存在 |
|
|
是, 如果调用setValue()创建或者 调用getValue()通过read-through创建 |
否 |
是, 如果调用remove() |
是, 如果调用 setValue() 更新 |
|
EntryProcessor
|
是, 如果调用setValue()创建或者 调用getValue()通过read-through创建 |
否 |
是, 如果调用remove() |
是, 如果调用 setValue() 更新 |
| Iterator
|
否 |
否 |
是, 如果调用remove() |
否 |
| void loadAll(Set keys,boolean replaceExistingValues, CompletionListener completionListener);
|
是,如果不存在 |
否 |
否 |
是,如果存在 |
| void put(K key, V value) |
是,如果不存在 |
否 |
否 |
是,如果存在 |
| void putAll(Map map) |
是,如果不存在 |
否 |
否 |
是,如果存在 |
| boolean putIfAbsent(K key, V value) |
是,如果不存在 |
否 |
否 |
否 |
| boolean remove(K key) |
否 |
否 |
是,如果存在 |
否 |
| boolean remove(K key, V oldValue) |
否 |
否 |
是,如果存在并且相等 |
否 |
| void removeAll() |
否 |
否 |
是,如果存在 |
否 |
| void removeAll(Set keys) |
否 |
否 |
是,如果存在 |
否 |
| boolean replace(K key, V value) |
否 |
否 |
否 |
是,如果存在 |
| boolean replace(K key, V oldValue, V newValue) |
否 |
否 |
否 |
是,如果存在并且相等 |
缓存条目执行器
一个javax.cache.Cache.EntryProcessor是一个可调用的功能,就像一个java.util.concurrent.Callable,应用程序可以用它来有效地执行组合的原子性的缓存操作,包括访问,更新和缓存条目,而不需要显式的锁或事务。
例如,可能希望检查一个缓存条目的值,计算出新的值,更新条目,并返回一些其他的值的原子操作,一个应用程序可以使用自定义的EntryProcessor实现来完成此功能。
javax.cache.Cache.EntryProcessor定义见下:
public interface EntryProcessor
/**
* 处理一个条目。
* @param entry 缓存条目
* @param arguments 处理的参数集合
* @return 处理的结果
*/
T process(Cache.MutableEntry
}
为了在缓存条目上调用EntryProcessor,应用必须使用Cache.invoke方法调用单个key的处理器及使用Cache.invoke