在这篇博文中,我们将继续介绍作为 Infinispan 8.0.0.Final 的一部分发布的实验性 Functional Map API,重点介绍如何使用单键操作来操作数据。
正如 Functional Map API 介绍 中提到的,可以对功能图执行三种类型的操作:只读操作(通过 ReadOnlyMap 执行)、只写操作(通过 WriteOnlyMap 执行)和读写操作(通过 ReadWriteMap ) 和 .
首先,我们需要构造 ReadOnlyMap 、 WriteOnlyMap 和 ReadWriteMap 的实例以便能够使用它们:
import org.infinispan.AdvancedCache;
import org.infinispan.commons.api.functional.FunctionalMap.*;
import org.infinispan.functional.impl.*;
import org.infinispan.manager.DefaultCacheManager;
DefaultCacheManager cacheManager = new DefaultCacheManager();
AdvancedCache<String, String> cache = cacheManager.<String, String>getCache().getAdvancedCache();
FunctionalMapImpl<String, String> functionalMap = FunctionalMapImpl.create(cache);
ReadOnlyMap<String, String> readOnlyMap = ReadOnlyMapImpl.create(functionalMap);
WriteOnlyMap<String, String> writeOnlyMap = WriteOnlyMapImpl.create(functionalMap);
ReadWriteMap<String, String> readWriteMap = ReadWriteMapImpl.create(functionalMap);
接下来,让我们看看所有三种类型的操作,将它们链接起来以存储单个键/值对以及一些元数据,然后读取它并最终删除并返回先前存储的数据:
import org.infinispan.AdvancedCache;
import org.infinispan.commons.api.functional.FunctionalMap.*;
import org.infinispan.functional.impl.*;
import org.infinispan.manager.DefaultCacheManager;
DefaultCacheManager cacheManager = new DefaultCacheManager();
AdvancedCache<String, String> cache = cacheManager.<String, String>getCache().getAdvancedCache();
FunctionalMapImpl<String, String> functionalMap = FunctionalMapImpl.create(cache);
ReadOnlyMap<String, String> readOnlyMap = ReadOnlyMapImpl.create(functionalMap);
WriteOnlyMap<String, String> writeOnlyMap = WriteOnlyMapImpl.create(functionalMap);
ReadWriteMap<String, String> readWriteMap = ReadWriteMapImpl.create(functionalMap);
此示例演示了使用 Functional Map API 处理单个条目的一些关键方面:
- 单一入口方法是异步返回 CompletableFuture 实例,它提供组合和链式操作的方法,因此可以感觉到它们是按顺序执行的。不幸的是,Java 没有 Haskell 的 do 表示法 或 Scala 的 for comprehensions 以使其更容易接受,但好消息是 Java 终于提供了以非阻塞方式使用 CompletableFutures 的机制,即使它们比提议的更冗长在其他语言中。
- WriteOnlyMap 的所有数据处理方法都返回 CompletableFuture<Void> ,这意味着用户可以知道操作何时完成,但除此之外别无其他,因为函数可以提供无法提前计算或在函数外部计算的任何内容。
- ReadOnlyMap (和 ReadWriteMap )中大多数数据处理方法的返回类型都非常灵活。因此,函数可以决定返回值信息或元数据,或者为了方便起见,它还可以返回它接收到的作为参数的 ReadEntryView。这对于想要返回值和元数据参数信息的用户很有用。
- 上面演示的读写操作展示了如何删除条目并返回先前关联的值。在这种特殊情况下,我们知道有一个与条目关联的值,因此我们直接调用了 ReadEntryView.get() ,但如果我们不确定该值是否存在,则应调用 ReadEntryView.find() 并返回 可选 实例代替。
- 在该示例中, Lifespan 元数据参数 是使用 Java 8 中可用的新 Java Time API 构造的,但只要转换为输入条目期间的毫秒数,也可以使用 java.util.concurrent.TimeUnit 完成同样的操作应该可以访问。
- 基于生命周期的到期与其他 Infinispan API 一样工作,因此您可以轻松修改示例以降低生命周期,等待持续时间过去,然后验证该值是否不再存在。
如果存储常量值,可以使用 WriteOnlyMap.eval(K, Consumer) 代替 WriteOnlyMap.eval(K, V, Consumer) ,使代码更清晰,但如果值是可变的, 则 WriteOnlyMap.eval(K, V, Consumer) 应该尽可能避免函数捕获外部变量。很显然,functional map 暴露的操作并不能覆盖所有场景,可能会出现函数捕获外部变量的情况,但一般来说,应该是少数。这是一个示例,显示如何在需要外部变量捕获的情况下实现 ConcurrentMap.replace(K, V, V) :
import org.infinispan.AdvancedCache;
import org.infinispan.commons.api.functional.FunctionalMap.*;
import org.infinispan.functional.impl.*;
import org.infinispan.manager.DefaultCacheManager;
DefaultCacheManager cacheManager = new DefaultCacheManager();
AdvancedCache<String, String> cache = cacheManager.<String, String>getCache().getAdvancedCache();
FunctionalMapImpl<String, String> functionalMap = FunctionalMapImpl.create(cache);
ReadOnlyMap<String, String> readOnlyMap = ReadOnlyMapImpl.create(functionalMap);
WriteOnlyMap<String, String> writeOnlyMap = WriteOnlyMapImpl.create(functionalMap);
ReadWriteMap<String, String> readWriteMap = ReadWriteMapImpl.create(functionalMap);
我们没有向 API 添加 WriteOnly.eval(K, V, V, Consumer) 的原因是基于值相等的替换比较只是一种可以执行的替换操作。在其他情况下,基于元数据参数的比较可能更合适,例如 Hot Rod 替换操作,其中版本(一种元数据参数)相等性是确定是否应该进行替换的决定性因素。
在下一篇博文中,我们将研究如何使用 Functional Map API 处理多个条目。