Ehcache 简介
1. 概述
在本文中,我们将介绍Ehcache ,一种广泛使用的、基于 Java 的开源缓存。它具有内存和磁盘存储、侦听器、缓存加载器、RESTful 和 SOAP API 以及其他非常有用的特性。
为了展示缓存如何优化我们的应用程序,我们将创建一个简单的方法来计算所提供数字的平方值。在每次调用时,该方法将调用*calculateSquareOfNumber(int number)*方法并将信息消息打印到控制台。
通过这个简单的示例,我们想展示平方值的计算只进行一次,并且具有相同输入值的每个其他调用都从缓存中返回结果。
需要注意的是,我们完全专注于 Ehcache 本身(没有 Spring);如果您想了解 Ehcache 如何与 Spring 一起工作,请阅读这篇文章 。
2. Maven依赖
为了使用 Ehcache,我们需要添加这个 Maven 依赖项:
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.1.3</version>
</dependency>
可以在此处 找到最新版本的 Ehcache 工件。
3. 缓存配置
Ehcache 可以通过两种方式进行配置:
- 第一种方式是通过 Java POJO,所有配置参数都通过 Ehcache API 进行配置
- 第二种方式是通过 XML 文件配置,我们可以根据提供的 schema 定义配置 Ehcache
在本文中,我们将展示这两种方法——Java 和 XML 配置。
3.1. Java 配置
本小节将展示使用 POJO 配置 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
}
要初始化我们的缓存,首先,我们需要定义 Ehcache CacheManager对象。在这个例子中,我们使用newCacheManagerBuilder() API创建一个默认的缓存squaredNumber” 。
缓存将简单地将Integer键映射到Integer值。
请注意,在我们开始使用定义的缓存之前,我们需要使用init()方法初始化CacheManager对象。
最后,要获取我们的缓存,我们可以使用getCache() API 和我们提供的缓存名称、键和值类型。
通过这几行代码,我们创建了我们的第一个缓存,它现在可供我们的应用程序使用。
3.2. XML 配置
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>
为了在我们的 Java 应用程序中包含这个缓存,我们需要在 Java 中读取 XML 配置文件:
URL myUrl = getClass().getResource(xmlFile);
XmlConfiguration xmlConfig = new XmlConfiguration(myUrl);
CacheManager myCacheManager = CacheManagerBuilder
.newCacheManager(xmlConfig);
4. Ehcache测试
在第 3 节中,我们展示了如何为您的目的定义简单缓存。为了证明缓存确实有效,我们将创建SquaredCalculator类,该类将计算所提供输入的平方值,并将计算的值存储在缓存中。
当然,如果缓存中已经包含计算值,我们会返回缓存值,避免不必要的计算:
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;
}
为了完成我们的测试场景,我们还需要计算平方值的代码:
@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");
}
}
如果我们运行我们的测试,我们将在控制台中得到这个结果:
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
如您所见,*calculate()*方法仅在第一次调用时进行计算。在第二次调用中,所有值都在缓存中找到并从中返回。
5. 其他 Ehcache 配置选项
当我们在前面的示例中创建缓存时,它是一个没有任何特殊选项的简单缓存。本节将显示在缓存创建中有用的其他选项。
5.1. 磁盘持久性
如果要存储到缓存中的值太多,我们可以将其中一些值存储在硬盘上。
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();
我们现在使用PersistentCacheManager代替默认的CacheManager ,它将持久化所有无法保存到内存中的值。 从配置中,我们可以看到缓存会将 10 个元素保存到内存中,并会在硬盘上分配 10MB 用于持久化。
5.2. 数据到期
如果我们缓存了很多数据,我们很自然地会把缓存的数据保存一段时间,这样我们就可以避免大量的内存使用。 Ehcache 通过Expiry接口控制数据的新鲜度:
CacheConfiguration<Integer, Integer> cacheConfiguration
= CacheConfigurationBuilder
.newCacheConfigurationBuilder(Integer.class, Integer.class,
ResourcePoolsBuilder.heap(100))
.withExpiry(Expirations.timeToLiveExpiration(Duration.of(60,
TimeUnit.SECONDS))).build();
在此缓存中,所有数据将存在 60 秒,在此时间段之后,它将从内存中删除。