JSR-107-JCache介绍

简介: JCache是JSR-107规范中定义了Java对象临时缓存在内存中的API和语义,包括对象的创建(object creation)、共享访问(shared access)、失效(invalidation)和跨JVM的一致性(consitency across jvm's)。简单说就是:JCache是Java提供的标准缓存API。

JCache简介

JCache是JSR-107规范中定义了Java对象临时缓存在内存中的API和语义,包括对象的创建(object creation)、共享访问(shared access)、失效(invalidation)和跨JVM的一致性(consitency across jvm's)。

简单说就是:JCache是Java提供的标准缓存API。

JSR(Java Sepecification Requests),即Java规范提案。


下面是JSR-107规范中定义对于Java cache的定义。

JSR-107

核心概念

在JCache中定义了五个核心接口:CachingProvider、CacheManager、Cache、Entry和ExpiryPolicy。

  • CachingProvider用于创建、配置、获取、管理和控制零个或多个CacheManager。应用程序在运行时可以访问或使用零个或多个CachingProvider。
  • CacheManager用于创建、配置、获取、管理和控制零个或多个唯一命名的Cache,这些Cache存在于CacheManager的上下文中。一个CacheManager只能归属一个CachingProvider。
  • Cache是类似Map的数据结构,用于临时存储基于key的value。一个Cache只能归属一个CacheManager。
  • Entry是存储在Cache中的键值对。
  • ExpiryPolicy定义了每个Entry在Cache中有效时间(TTL),有效期内Entry能够被访问、修改和删除,有效期后该Entry不能在被访问、修改和删除。


对应关系如下:

值存储和引用存储

JSR-107中定义了两种Cache存储Entry的方法,即按值存储(Store-By-Value)和按引用存储(Store-By-Reference)。

  • 按值存储是默认机制,也就是在存储kv对时,先对key和value进行拷贝,然后将拷贝的副本存储到Cache中。当访问Cache时,返回的是数据的副本。
  • 按引用存储是另外一种可选的机制,存储kv对时,Cache中存储的是Key和Value的引用。当应用程序修改kv对时,应用程序无需再次修改Cache中的数据。


一致性

一致性是指当并发访问缓存时,需要保证修改的可见性在并发线程/进程间是一致的。为了保证一致性,所有的实现框架都应该支持以下默认一致性模型。


默认一致性模型

在执行大部分Cache操作时,就好像为Cache中的每个Key加了锁,当某个操作获取该key的排它性读写锁时,后面对该key的所有操作都会被阻塞,直到这个锁释放。注意,这里的操作可以是单个JVM进程内的,也可以是跨JVM的操作。

对于某些具有返回值的Cache操作,返回的缓存值需要是最新值。但是这个最新值,可以根据缓存的具体实现定义,比如当并发修改时,这个返回值可以是修改前的值,也可以是修改后的值。


Cache和Map的差异

Cache和Map两者之间有一些共性点,但是二者不是同一个东西。下面是二者之间的相同点与不同点:

相同点:

  • 都是通过Key进行存储和访问。
  • 每个Key都与一个Value对应。
  • 当使用可变对象作为Key时,修改Key值可能引发查询对比的未知。
  • 使用自定义类作为Key时,都需要显示实现Object.hashCode()方法。


不同点:

  • Cache的Key和value不许为null,如果设置了null,则会抛出NullPointerException。
  • Cache中的Entry可能会过期(Expire)。
  • Cache中的Entry可能被驱逐(Evicted)。
  • 为了支持原子比较和交换(compare-and-swap, CAP),Cache中的自定义应提供Object.equals()方法的实现。
  • Cache中的Key和Value是需要可被序列化的。
  • Cache可以设置使用值存储或引用存储来存储Entry实例。
  • Cache是可以选择强制的安全性限制,如果违规操作,可以抛出SecurityException异常。


JCache demo

引入依赖:

<dependency><groupId>javax.cache</groupId><artifactId>cache-api</artifactId><version>1.1.1</version></dependency>


下面是JCache的使用demo。

CachingProviderprovider=Caching.getCachingProvider();
CacheManagercacheManager=provider.getCacheManager();
MutableConfiguration<String, Integer>config=newMutableConfiguration<>();
config.setTypes(String.class, Integer.class);
config.setExpiryPolicyFactory(AccessedExpiryPolicy.factoryOf(Duration.ONE_HOUR));
Cache<String, Integer>cache=cacheManager.createCache("testCache", config);
cache.put("test1", 1);
cache.put("test2", 2);
System.out.println(cache.get("test1"));
System.out.println(cache.get("test2"));
cache.remove("test1");
System.out.println(cache.get("test2"));

 

需要注意的是我们没有提供实现框架,所以运行过程中会抛出以下异常,原因是JVM找不到getCacheManager()方法的任何实现。

Exceptioninthread"main"javax.cache.CacheException: NoCachingProvidershavebeenconfigured


源码分析

下面是JCache的源码,比较精简。

CachingProvider

CachingProvider是一个接口,我们可以用于创建和管理CacheManager的生命周期。

publicinterfaceCachingProviderextendsCloseable {
CacheManagergetCacheManager(URIuri, ClassLoaderclassLoader,
Propertiesproperties);
ClassLoadergetDefaultClassLoader();
URIgetDefaultURI();
PropertiesgetDefaultProperties();
CacheManagergetCacheManager(URIuri, ClassLoaderclassLoader);
CacheManagergetCacheManager();
voidclose();
voidclose(ClassLoaderclassLoader);
voidclose(URIuri, ClassLoaderclassLoader);
booleanisSupported(OptionalFeatureoptionalFeature);
}


CacheManager

CacheManager是JCache API最重要的接口之一,他提供了创建、配置和销毁Cache的方法。

publicinterfaceCacheManagerextendsCloseable {
CachingProvidergetCachingProvider();
URIgetURI();
ClassLoadergetClassLoader();
PropertiesgetProperties();
<K, V, CextendsConfiguration<K, V>>Cache<K, V>createCache(StringcacheName,
Cconfiguration)
throwsIllegalArgumentException;
<K, V>Cache<K, V>getCache(StringcacheName, Class<K>keyType,
Class<V>valueType);
<K, V>Cache<K, V>getCache(StringcacheName);
Iterable<String>getCacheNames();
voiddestroyCache(StringcacheName);
voidenableManagement(StringcacheName, booleanenabled);
voidenableStatistics(StringcacheName, booleanenabled);
voidclose();
booleanisClosed();
<T>Tunwrap(java.lang.Class<T>clazz);
}

Cache & Entry


Entry是Cache的内部接口:

publicinterfaceCache<K, V>extendsIterable<Cache.Entry<K, V>>, Closeable {
Vget(Kvar1);
Map<K, V>getAll(Set<?extendsK>var1);
booleancontainsKey(Kvar1);
voidloadAll(Set<?extendsK>var1, booleanvar2, CompletionListenervar3);
voidput(Kvar1, Vvar2);
VgetAndPut(Kvar1, Vvar2);
voidputAll(Map<?extendsK, ?extendsV>var1);
booleanputIfAbsent(Kvar1, Vvar2);
booleanremove(Kvar1);
booleanremove(Kvar1, Vvar2);
VgetAndRemove(Kvar1);
booleanreplace(Kvar1, Vvar2, Vvar3);
booleanreplace(Kvar1, Vvar2);
VgetAndReplace(Kvar1, Vvar2);
voidremoveAll(Set<?extendsK>var1);
voidremoveAll();
voidclear();
<CextendsConfiguration<K, V>>CgetConfiguration(Class<C>var1);
<T>Tinvoke(Kvar1, EntryProcessor<K, V, T>var2, Object... var3) throwsEntryProcessorException;
<T>Map<K, EntryProcessorResult<T>>invokeAll(Set<?extendsK>var1, EntryProcessor<K, V, T>var2, Object... var3);
StringgetName();
CacheManagergetCacheManager();
voidclose();
booleanisClosed();
<T>Tunwrap(Class<T>var1);
voidregisterCacheEntryListener(CacheEntryListenerConfiguration<K, V>var1);
voidderegisterCacheEntryListener(CacheEntryListenerConfiguration<K, V>var1);
Iterator<Cache.Entry<K, V>>iterator();
publicinterfaceEntry<K, V> {
KgetKey();
VgetValue();
<T>Tunwrap(Class<T>var1);
  }
}


Configuration

配置类:


ExpiryPolicy

KV过期策略:


参考


https://www.jcp.org/en/jsr/detail?id=107

https://www.javadoc.io/doc/javax.cache/cache-api/1.0.0/javax/cache/package-summary.html

https://docs.oracle.com/middleware/1213/coherence/develop-applications/jcache_intro.htm#COHDG5778

https://docs.google.com/document/d/1ijduF_tmHvBaUS7VBBU2ZN8_eEBiFaXXg9OI0_ZxCrA/edit

https://www.ctolib.com/topics-143462.html

https://www.jianshu.com/p/f6a1eae03efb

相关文章
|
Oracle 关系型数据库 数据库
人大金仓数据库使用uuid
人大金仓数据库使用uuid
人大金仓数据库使用uuid
|
缓存 NoSQL Java
【JetCache】JetCache的使用方法与步骤
【JetCache】JetCache的使用方法与步骤
9103 1
|
消息中间件 SQL 存储
超详细的RabbitMQ入门,看这篇就够了!
RabbitMQ入门,看这篇就够了
222562 69
|
存储 Linux 应用服务中间件
基于CentOS 7.6的Docker新手教学
采用本地虚拟机+阿里云镜像加速器
1618 5
基于CentOS 7.6的Docker新手教学
|
XML 缓存 NoSQL
玩转Spring Cache --- 整合进程缓存之王Caffeine Cache和Ehcache3.x【享学Spring】(下)
玩转Spring Cache --- 整合进程缓存之王Caffeine Cache和Ehcache3.x【享学Spring】(下)
|
缓存 安全 Java
全面解读ConcurrentHashMap:Java中的高效并发数据结构
全面解读ConcurrentHashMap:Java中的高效并发数据结构
2706 2
|
存储 XML 缓存
【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache功能的开发实战指南(一)
【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache功能的开发实战指南
1211 0
|
JavaScript
rollup的input配置和output配置详解
【8月更文挑战第5天】rollup的input配置和output配置详解
622 4
rollup的input配置和output配置详解
|
存储 Java 测试技术
阿里巴巴java开发手册
这篇文章是关于阿里巴巴Java开发手册的整理,内容包括编程规约、异常日志、单元测试、安全规约、MySQL数据库使用以及工程结构等方面的详细规范和建议,旨在帮助开发者编写更加规范、高效和安全的代码。
|
存储 算法 安全
深入解析消息认证码(MAC)算法:HmacMD5与HmacSHA1
深入解析消息认证码(MAC)算法:HmacMD5与HmacSHA1