Introduction to JCache – JCache简介

最后修改: 2017年 9月 11日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Simply put, JCache is the standard caching API for Java. In this tutorial, we’re going to see what JCache is and how we can use it.

简单地说,JCache是Java的标准高速缓存API。在本教程中,我们将看到什么是JCache以及如何使用它。

2. Maven Dependencies

2.Maven的依赖性

To use JCache, we need to add the following dependency to our pom.xml:

为了使用JCache,我们需要在我们的pom.xml中添加以下依赖关系。

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

Note that we can find the latest version of the library in the Maven Central Repository.

注意,我们可以在Maven Central Repository中找到该库的最新版本。

We also need to add an implementation of the API to our pom.xml; we’ll use Hazelcast here:

我们还需要在我们的pom.xml中添加一个API的实现;我们将在这里使用Hazelcast。

<dependency>
    <groupId>com.hazelcast</groupId>
    <artifactId>hazelcast</artifactId>
    <version>5.2.0</version>
</dependency>

We can also find the latest version of Hazelcast in its Maven Central Repository.

我们还可以在Hazelcast的Maven中央仓库中找到最新版本。

3. JCache Implementations

3.JCache的实施

JCache is implemented by various caching solutions:

JCache是由各种缓存解决方案实现的。

  • JCache Reference Implementation
  • Hazelcast
  • Oracle Coherence
  • Terracotta Ehcache
  • Infinispan

Note that, unlike other reference implementations, it’s not recommended to use JCache Reference Implementation in production since it causes some concurrency issues.

请注意,与其他参考实现不同,不建议在生产中使用JCache参考实现,因为它会导致一些并发问题。

4. Main Components

4.主要成分

4.1. Cache

4.1.缓存

The Cache interface has the following useful methods:

Cache接口有以下有用的方法。

  • get() – takes the key of an element as a parameter and returns the value of the element; it returns null if the key does not exist in the Cache
  • getAll() – multiple keys can be passed to this method as a Set; the method returns the given keys and associated values as a Map
  • getAndRemove() – the method retrieves a value using its key and removes the element from the Cache
  • put() – inserts a new item in the Cache
  • clear() – removes all elements in the Cache
  • containsKey() – checks if a Cache contains a particular key

As we can see, the methods’ names are pretty much self-explanatory. For more information on these methods and other ones, visit the Javadoc.

正如我们所看到的,这些方法的名称几乎是不言自明的。关于这些方法和其他方法的更多信息,请访问Javadoc

4.2. CacheManager

4.2.CacheManager

CacheManager is one of the most important interfaces of the API. It enables us to establish, configure and close Caches.

CacheManager是API中最重要的接口之一。它使我们能够建立、配置和关闭Cache

4.3. CachingProvider

4.3.CachingProvider

CachingProvider is an interface which allows us to create and manage the lifecycle of CacheManagers.

CachingProvider是一个接口,允许我们创建和管理CacheManagers的生命周期。

4.4. Configuration

4.4.配置

Configuration is an interface that enables us to configure Caches. It has one concrete implementation – MutableConfiguration and a subinterface – CompleteConfiguration.

Configuration是一个接口,使我们能够配置Caches。它有一个具体的实现 – MutableConfiguration 和一个子接口 – CompleteConfiguration

5. Creating a Cache

5.创建一个缓存

Let’s see how we can create a simple Cache:

让我们看看如何创建一个简单的Cache

CachingProvider cachingProvider = Caching.getCachingProvider();
CacheManager cacheManager = cachingProvider.getCacheManager();
MutableConfiguration<String, String> config
  = new MutableConfiguration<>();
Cache<String, String> cache = cacheManager
  .createCache("simpleCache", config);
cache.put("key1", "value1");
cache.put("key2", "value2");
cacheManager.close();

All we’re doing is:

我们所要做的就是

  • Creating a CachingProvider object, which we are using to construct a CacheManager object
  • Creating a MutableConfiguration object, which is an implementation of the Configuration interface
  • Creating a Cache object using the CacheManager object we created earlier
  • Putting all the entries, we need to cache into our Cache object
  • Closing the CacheManager to release the resources used by the Cache

If we do not provide any implementation of JCache in our pom.xml, the following exception will be thrown:

如果我们在pom.xml中没有提供任何JCache的实现,将抛出以下异常:

javax.cache.CacheException: No CachingProviders have been configured

The reason for this is that the JVM could not find any concrete implementation of the getCacheManager() method.

其原因是JVM无法找到getCacheManager()方法的任何具体实现

6. EntryProcessor

6.EntryProcessor

EntryProcessor allows us to modify Cache entries using atomic operations without having to re-add them to the Cache. To use it, we need to implement the EntryProcessor interface:

EntryProcessor允许我们使用原子操作来修改Cache条目,而不必将它们重新添加到Cache中。要使用它,我们需要实现EntryProcessor接口。

public class SimpleEntryProcessor
  implements EntryProcessor<String, String, String>, Serializable {
    
    public String process(MutableEntry<String, String> entry, Object... args)
      throws EntryProcessorException {

        if (entry.exists()) {
            String current = entry.getValue();
            entry.setValue(current + " - modified");
            return current;
        }
        return null;
    }
}

Now, let’s use our EntryProcessor implementation:

现在,让我们使用我们的EntryProcessor实现。

@Test
public void whenModifyValue_thenCorrect() {
    this.cache.invoke("key", new SimpleEntryProcessor());
 
    assertEquals("value - modified", cache.get("key"));
}

7. Event Listeners

7.事件监听器

Event Listeners allow us to take actions upon triggering any of the event types defined in the EventType enum, which are:

事件监听器允许我们在触发EventType枚举中定义的任何事件类型时采取行动,这些事件类型包括。

  • CREATED
  • UPDATED
  • REMOVED
  • EXPIRED

First, we need to implement interfaces of the events we’re going to use.

首先,我们需要实现我们要使用的事件的接口。

For example, if we want to use the CREATED and the UPDATED event types, then we should implement the interfaces CacheEntryCreatedListener and CacheEntryUpdatedListener.

例如,如果我们想使用CREATEDUPDATED事件类型,那么我们应该实现CacheEntryCreatedListenerCacheEntryUpdatedListener接口。

Let’s see an example:

让我们看一个例子。

public class SimpleCacheEntryListener implements
  CacheEntryCreatedListener<String, String>,
  CacheEntryUpdatedListener<String, String>,
  Serializable {
    
    private boolean updated;
    private boolean created;
    
    // standard getters
    
    public void onUpdated(
      Iterable<CacheEntryEvent<? extends String,
      ? extends String>> events) throws CacheEntryListenerException {
        this.updated = true;
    }
    
    public void onCreated(
      Iterable<CacheEntryEvent<? extends String,
      ? extends String>> events) throws CacheEntryListenerException {
        this.created = true;
    }
}

Now, let’s run our test:

现在,让我们运行我们的测试。

@Test
public void whenRunEvent_thenCorrect() throws InterruptedException {
    this.listenerConfiguration
      = new MutableCacheEntryListenerConfiguration<String, String>(
        FactoryBuilder.factoryOf(this.listener), null, false, true);
    this.cache.registerCacheEntryListener(this.listenerConfiguration);
    
    assertEquals(false, this.listener.getCreated());
    
    this.cache.put("key", "value");
 
    assertEquals(true, this.listener.getCreated());
    assertEquals(false, this.listener.getUpdated());
    
    this.cache.put("key", "newValue");
 
    assertEquals(true, this.listener.getUpdated());
}

8. CacheLoader

8.CacheLoader

CacheLoader allows us to use read-through mode to treat cache as the main data store and read data from it.

CacheLoader允许我们使用透读模式将缓存视为主要的数据存储,并从其中读取数据

In a real-world scenario, we can have the cache read data from actual storage.

在现实世界中,我们可以让缓存从实际存储中读取数据。

Let’s have a look at an example. First, we should implement the CacheLoader interface:

让我们来看看一个例子。首先,我们应该实现CacheLoader接口。

public class SimpleCacheLoader
  implements CacheLoader<Integer, String> {

    public String load(Integer key) throws CacheLoaderException {
        return "fromCache" + key;
    }
    
    public Map<Integer, String> loadAll(Iterable<? extends Integer> keys)
      throws CacheLoaderException {
        Map<Integer, String> data = new HashMap<>();
        for (int key : keys) {
            data.put(key, load(key));
        }
        return data;
    }
}

And now, let’s use our CacheLoader implementation:

现在,让我们使用我们的CacheLoader实现。

public class CacheLoaderIntegrationTest {
    
    private Cache<Integer, String> cache;
    
    @Before
    public void setup() {
        CachingProvider cachingProvider = Caching.getCachingProvider();
        CacheManager cacheManager = cachingProvider.getCacheManager();
        MutableConfiguration<Integer, String> config
          = new MutableConfiguration<>()
            .setReadThrough(true)
            .setCacheLoaderFactory(new FactoryBuilder.SingletonFactory<>(
              new SimpleCacheLoader()));
        this.cache = cacheManager.createCache("SimpleCache", config);
    }
    
    @Test
    public void whenReadingFromStorage_thenCorrect() {
        for (int i = 1; i < 4; i++) {
            String value = cache.get(i);
 
            assertEquals("fromCache" + i, value);
        }
    }
}

9. Conclusion

9.结论

In this tutorial, we’ve seen what JCache is and explored some of its important features in a few practical scenarios.

在本教程中,我们已经看到了什么是JCache,并在一些实际场景中探索了它的一些重要功能。

As always, the full implementation of this tutorial can be found over on GitHub.

一如既往,本教程的完整实现可以在GitHub上找到over