Introduction To Ehcache – Ehcache简介

最后修改: 2016年 10月 20日

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

1. Overview

1.概述

In this article, we will introduce Ehcache, a widely used, open-source Java-based cache. It features memory and disk stores, listeners, cache loaders, RESTful and SOAP APIs and other very useful features.

在这篇文章中,我们将介绍Ehcache,这是一个广泛使用的、基于Java的开源缓存。它具有内存和磁盘存储、监听器、缓存加载器、RESTful和SOAP API以及其他非常有用的功能。

To show how caching can optimize our application, we will create a simple method which will calculate square values of provided numbers. On each call, the method will call calculateSquareOfNumber(int number) method and print information message to the console.

为了展示缓存如何优化我们的应用程序,我们将创建一个简单的方法来计算所提供数字的平方值。在每次调用时,该方法将调用calculateSquareOfNumber(int number)方法并向控制台打印信息。

With this simple example, we want to show that calculation of squared values is done only once, and every other call with same input value is returning result from cache.

通过这个简单的例子,我们想说明,平方值的计算只做了一次,而其他每一次输入值相同的调用都是从缓存中返回结果。

It’s important to notice that we’re focused entirely on Ehcache itself (without Spring); if you want to see how Ehcache works with Spring, have a look at read this article.

需要注意的是,我们完全专注于Ehcache本身(不包括Spring);如果你想看看Ehcache是如何与Spring一起工作的,可以看看阅读这篇文章

2. Maven Dependencies

2.Maven的依赖性

In order to use Ehcache we need to add this Maven dependency:

为了使用Ehcache,我们需要添加这个Maven依赖项。

<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.1.3</version>
</dependency>

The latest version of the Ehcache artifact can be found here.

最新版本的Ehcache构件可以在这里找到。

3. Cache Configuration

3.缓存配置

Ehcache can be configured in two ways:

Ehcache可以通过两种方式进行配置。

  • The first way is through Java POJO where all configuration parameters are configured through Ehcache API
  • The second way is configuration through XML file where we can configure Ehcache according to provided schema definition

In this article, we’ll show both approaches – Java as well as XML configuration.

在这篇文章中,我们将展示两种方法–Java以及XML配置。

3.1. Java Configuration

3.1. Java配置

This subsection will show how easy it is to configure Ehcache with POJOs. Also, we will create a helper class for easier cache configuration and availability:

本小节将展示用POJOs配置Ehcache是多么容易。同时,我们将创建一个辅助类,以使缓存的配置和可用性更容易。

public class CacheHelper {

    private CacheManager cacheManager;
    private Cache<Integer, Integer> squareNumberCache;

    public CacheHelper() {
        cacheManager = CacheManagerBuilder
          .newCacheManagerBuilder().build();
        cacheManager.init();

        squareNumberCache = cacheManager
          .createCache("squaredNumber", CacheConfigurationBuilder
            .newCacheConfigurationBuilder(
              Integer.class, Integer.class,
              ResourcePoolsBuilder.heap(10)));
    }

    public Cache<Integer, Integer> getSquareNumberCacheFromCacheManager() {
        return cacheManager.getCache("squaredNumber", Integer.class, Integer.class);
    }
    
    // standard getters and setters
}

To initialize our cache, first, we need to define Ehcache CacheManager object. In this example, we are creating a default cache squaredNumber” with the newCacheManagerBuilder() API.

为了初始化我们的缓存,首先,我们需要定义Ehcache CacheManager 对象。在这个例子中,我们用newCacheManagerBuilder() API创建一个默认的缓存 squaredNumber”

The cache will simply map Integer keys to Integer values.

缓存将简单地把Integer键映射到Integer值。

Notice how, before we start using the defined cache, we need to initialize the CacheManager object with the init() method.

注意,在我们开始使用定义的缓存之前,我们需要用init()方法初始化CacheManager对象。

Finally, to obtain our cache, we can just use the getCache() API with the provided name, key and value types of our cache.

最后,为了获得我们的缓存,我们可以直接使用getCache() API,并提供我们的缓存的名称、键和值类型。

With those few lines, we created our first cache which is now available to our application.

通过这几行字,我们创建了第一个缓存,现在可以供我们的应用程序使用。

3.2. XML Configuration

3.2.XML配置

The configuration object from subsection 3.1. is equal to using this XML configuration:

3.1.小节中的配置对象等于使用这个XML配置。

<cache-template name="squaredNumber">
    <key-type>java.lang.Integer</key-type>
    <value-type>java.lang.Integer</value-type>
    <heap unit="entries">10</heap>
</cache-template>

And to include this cache in our Java application, we need to read XML configuration file in Java:

而要在我们的Java应用程序中包含这个缓存,我们需要在Java中读取XML配置文件。

URL myUrl = getClass().getResource(xmlFile); 
XmlConfiguration xmlConfig = new XmlConfiguration(myUrl); 
CacheManager myCacheManager = CacheManagerBuilder
  .newCacheManager(xmlConfig);

4. Ehcache Test

4.Ehcache测试

In section 3. we showed how you can define simple cache for your purposes. To show that caching actually works, we will create SquaredCalculator class which will calculate squared value of the provided input, and store calculated value in a cache.

在第3节,我们展示了如何为你的目的定义简单的缓存。为了证明缓存的实际作用,我们将创建SquaredCalculator类,它将计算所提供的输入的平方值,并将计算值存储在一个缓存中。

Of course, if cache already contains calculated value, we will return cached value and avoid unnecessary calculations:

当然,如果缓存已经包含了计算值,我们将返回缓存的值,避免不必要的计算。

public class SquaredCalculator {
    private CacheHelper cache;

    public int getSquareValueOfNumber(int input) {
        if (cache.getSquareNumberCache().containsKey(input)) {
            return cache.getSquareNumberCache().get(input);
        }

        System.out.println("Calculating square value of " + input + 
          " and caching result.");

        int squaredValue = (int) Math.pow(input, 2);
        cache.getSquareNumberCache().put(input, squaredValue);

        return squaredValue;
    }

    //standard getters and setters;
}

To complete our test scenario, we will also need the code which will calculate square values:

为了完成我们的测试方案,我们还需要计算平方值的代码。

@Test
public void whenCalculatingSquareValueAgain_thenCacheHasAllValues() {
    for (int i = 10; i < 15; i++) {
        assertFalse(cacheHelper.getSquareNumberCache().containsKey(i));
        System.out.println("Square value of " + i + " is: "
          + squaredCalculator.getSquareValueOfNumber(i) + "\n");
    }      
    
    for (int i = 10; i < 15; i++) {
        assertTrue(cacheHelper.getSquareNumberCache().containsKey(i));
        System.out.println("Square value of " + i + " is: "
          + squaredCalculator.getSquareValueOfNumber(i) + "\n");
    }
}

If we run our test, we will get this result in our console:

如果我们运行我们的测试,我们将在控制台得到这样的结果。

Calculating square value of 10 and caching result.
Square value of 10 is: 100

Calculating square value of 11 and caching result.
Square value of 11 is: 121

Calculating square value of 12 and caching result.
Square value of 12 is: 144

Calculating square value of 13 and caching result.
Square value of 13 is: 169

Calculating square value of 14 and caching result.
Square value of 14 is: 196

Square value of 10 is: 100
Square value of 11 is: 121
Square value of 12 is: 144
Square value of 13 is: 169
Square value of 14 is: 196

As you can notice, calculate() method was doing calculations only on first call. On the second call, all values were found in the cache and returned from it.

你可以注意到,calculate()方法只在第一次调用时进行计算。在第二次调用时,所有的值都在缓存中找到,并从缓存中返回。

5. Other Ehcache Configuration Options

5.其他Ehcache配置选项

When we created our cache in the previous example, it was a simple cache without any special options. This section will show other options which are useful in cache creation.

当我们在前面的例子中创建我们的缓冲区时,它是一个简单的缓冲区,没有任何特殊的选项。本节将介绍在创建缓冲区时有用的其他选项。

5.1. Disk Persistence

5.1 磁盘持久性

If there are too many values to store into the cache, we can store some of those values on the hard drive.

如果有太多的值需要存储到缓存中,我们可以将其中的一些值存储到硬盘上。

PersistentCacheManager persistentCacheManager = 
  CacheManagerBuilder.newCacheManagerBuilder()
    .with(CacheManagerBuilder.persistence(getStoragePath()
      + File.separator 
      + "squaredValue")) 
    .withCache("persistent-cache", CacheConfigurationBuilder
      .newCacheConfigurationBuilder(Integer.class, Integer.class,
        ResourcePoolsBuilder.newResourcePoolsBuilder()
          .heap(10, EntryUnit.ENTRIES)
          .disk(10, MemoryUnit.MB, true)) 
      )
  .build(true);

persistentCacheManager.close();

Instead of default CacheManager, we now use PersistentCacheManager which will persist all values which can’t be saved into memory.

我们现在不使用默认的CacheManager,而是使用PersistentCacheManager,它将持久化所有不能保存到内存中的值。

From configuration, we can see that cache will save 10 elements into memory and it will allocate 10MB on the hard drive for persistence.

从配置中,我们可以看到,缓存将把10个元素保存在内存中,它将在硬盘上分配10MB用于持久化。

5.2. Data Expiry

5.2.数据过期

If we cache a lot of data, it’s natural that we save cached data for some period of time so we can avoid big memory usage.

如果我们缓存了大量的数据,很自然地,我们会将缓存的数据保存一段时间,这样我们就可以避免大的内存使用。

Ehcache controls data freshness trough Expiry interface:

Ehcache通过Expiry接口来控制数据的新鲜度。

CacheConfiguration<Integer, Integer> cacheConfiguration 
  = CacheConfigurationBuilder
    .newCacheConfigurationBuilder(Integer.class, Integer.class, 
      ResourcePoolsBuilder.heap(100)) 
    .withExpiry(Expirations.timeToLiveExpiration(Duration.of(60, 
      TimeUnit.SECONDS))).build();

In this cache, all data will live for 60 seconds and after that period of time, it will be deleted from memory.

在这个缓存中,所有的数据将存活60秒,过了这段时间,它就会从内存中删除。

6. Conclusion

6.结论

In this article, we showed how to use simple Ehcache caching in a Java application.

在这篇文章中,我们展示了如何在一个Java应用程序中使用简单的Ehcache缓存。

In our example, we saw that even a simply configured cache can save a lot of unnecessary operations. Also, we showed that we can configure caches through POJOs and XML and that Ehcache has quite some nice features – such as persistence and data expiry.

在我们的例子中,我们看到即使是一个简单配置的缓存也可以节省很多不必要的操作。另外,我们还展示了我们可以通过POJO和XML来配置缓存,而且Ehcache有相当不错的功能–比如持久性和数据过期。

As always, the code from this article can be found on GitHub.

一如既往,本文的代码可以在GitHub上找到