JSR-107-JCache介绍

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-JCache介绍

值存储和引用存储

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。

CachingProvider provider = Caching.getCachingProvider();
CacheManager cacheManager = provider.getCacheManager();
MutableConfiguration<String, Integer> config = new MutableConfiguration<>();
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()方法的任何实现。

Exception in thread "main" javax.cache.CacheException: No CachingProviders have been configured


源码分析

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

JSR-107-JCache介绍

CachingProvider

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

public interface CachingProvider extends Closeable {
  CacheManager getCacheManager(URI uri, ClassLoader classLoader,
                               Properties properties);
  ClassLoader getDefaultClassLoader();
  URI getDefaultURI();
  Properties getDefaultProperties();
  CacheManager getCacheManager(URI uri, ClassLoader classLoader);
  CacheManager getCacheManager();
  void close();
  void close(ClassLoader classLoader);
  void close(URI uri, ClassLoader classLoader);
  boolean isSupported(OptionalFeature optionalFeature);
}


CacheManager

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

public interface CacheManager extends Closeable {
  CachingProvider getCachingProvider();
  URI getURI();
  ClassLoader getClassLoader();
 
  Properties getProperties();
  <K, V, C extends Configuration<K, V>> Cache<K, V> createCache(String cacheName,
                                                                C configuration)
      throws IllegalArgumentException;
  <K, V> Cache<K, V> getCache(String cacheName, Class<K> keyType,
                              Class<V> valueType);
  <K, V> Cache<K, V> getCache(String cacheName);
  Iterable<String> getCacheNames();
  void destroyCache(String cacheName);
  void enableManagement(String cacheName, boolean enabled);
  void enableStatistics(String cacheName, boolean enabled);
  void close();
  boolean isClosed();
  <T> T unwrap(java.lang.Class<T> clazz);
}

Cache & Entry


Entry是Cache的内部接口:

public interface Cache<K, V> extends Iterable<Cache.Entry<K, V>>, Closeable {
  V get(K var1);
  Map<K, V> getAll(Set<? extends K> var1);
  boolean containsKey(K var1);
  void loadAll(Set<? extends K> var1, boolean var2, CompletionListener var3);
  void put(K var1, V var2);
  V getAndPut(K var1, V var2);
  void putAll(Map<? extends K, ? extends V> var1);
  boolean putIfAbsent(K var1, V var2);
  boolean remove(K var1);
  boolean remove(K var1, V var2);
  V getAndRemove(K var1);
  boolean replace(K var1, V var2, V var3);
  boolean replace(K var1, V var2);
  V getAndReplace(K var1, V var2);
  void removeAll(Set<? extends K> var1);
  void removeAll();
  void clear();
  <C extends Configuration<K, V>> C getConfiguration(Class<C> var1);
  <T> T invoke(K var1, EntryProcessor<K, V, T> var2, Object... var3) throws EntryProcessorException;
  <T> Map<K, EntryProcessorResult<T>> invokeAll(Set<? extends K> var1, EntryProcessor<K, V, T> var2, Object... var3);
  String getName();
  CacheManager getCacheManager();
  void close();
  boolean isClosed();
  <T> T unwrap(Class<T> var1);
  void registerCacheEntryListener(CacheEntryListenerConfiguration<K, V> var1);
  void deregisterCacheEntryListener(CacheEntryListenerConfiguration<K, V> var1);
  Iterator<Cache.Entry<K, V>> iterator();
  public interface Entry<K, V> {
    K getKey();
    V getValue();
    <T> T unwrap(Class<T> var1);
  }
}


Configuration

配置类:

JSR-107-JCache介绍


ExpiryPolicy

KV过期策略:

JSR-107-JCache介绍


参考


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

上一篇:购买阿里云服务器之后部署FTP站点和Web环境教程


下一篇:阿里云服务器一次购买三年的好处、优惠政策及具体价格介绍