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

相关文章
|
5月前
|
XML 搜索推荐 Java
JAXB的常用注解讲解
JAXB的常用注解讲解
|
6月前
|
缓存 前端开发 Java
JSR303与拦截器的使用
JSR303与拦截器的使用
51 0
|
监控 Java API
“JSR303和拦截器在Java Web开发中的应用与实践“
“JSR303和拦截器在Java Web开发中的应用与实践“
45 0
|
存储 缓存 中间件
JSR107 简介|学习笔记
快速学习 JSR107 简介
100 0
JSR107 简介|学习笔记
|
XML Java 关系型数据库
深入了解数据校验:Java Bean Validation 2.0(JSR303、JSR349、JSR380)Hibernate-Validation 6.x使用案例【享学Java】(上)
深入了解数据校验:Java Bean Validation 2.0(JSR303、JSR349、JSR380)Hibernate-Validation 6.x使用案例【享学Java】(上)
深入了解数据校验:Java Bean Validation 2.0(JSR303、JSR349、JSR380)Hibernate-Validation 6.x使用案例【享学Java】(上)
|
XML 缓存 安全
深入了解数据校验:Java Bean Validation 2.0(JSR303、JSR349、JSR380)Hibernate-Validation 6.x使用案例【享学Java】(中)
深入了解数据校验:Java Bean Validation 2.0(JSR303、JSR349、JSR380)Hibernate-Validation 6.x使用案例【享学Java】(中)
深入了解数据校验:Java Bean Validation 2.0(JSR303、JSR349、JSR380)Hibernate-Validation 6.x使用案例【享学Java】(中)
|
Java Spring
Spring - JSR-330 标准注解(二)
Spring - JSR-330 标准注解(二)
243 0
Spring - JSR-330 标准注解(二)
|
存储 安全 JavaScript
【小家java】java8新特性之---全新的日期、时间API(JSR 310规范),附SpringMVC、Mybatis中使用JSR310的正确姿势(上)
【小家java】java8新特性之---全新的日期、时间API(JSR 310规范),附SpringMVC、Mybatis中使用JSR310的正确姿势(上)
【小家java】java8新特性之---全新的日期、时间API(JSR 310规范),附SpringMVC、Mybatis中使用JSR310的正确姿势(上)
|
存储 Java 数据库连接
【小家java】java8新特性之---全新的日期、时间API(JSR 310规范),附SpringMVC、Mybatis中使用JSR310的正确姿势(中)
【小家java】java8新特性之---全新的日期、时间API(JSR 310规范),附SpringMVC、Mybatis中使用JSR310的正确姿势(中)
【小家java】java8新特性之---全新的日期、时间API(JSR 310规范),附SpringMVC、Mybatis中使用JSR310的正确姿势(中)