官网地址:http://×××w.ehcache.org/documentation/3.6/getting-started.html
根据官网的说明使用起来非常简单,尤其是在3.0之后, 不管事xml配置文件还是链式编码配置。
先看示例:
ResourcePoolsBuilder resourcePoolsBuilder = ResourcePoolsBuilder.newResourcePoolsBuilder().heap(20, MemoryUnit.MB).offheap(30, MemoryUnit.MB);
CacheConfiguration<String, Object> cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, Object.class, resourcePoolsBuilder)
.withValueSerializer(new PlainJavaSerializer<>(this.getClass().getClassLoader()))
.withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofHours(24))).build();
org.ehcache.CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.withDefaultSizeOfMaxObjectSize(500, MemoryUnit.KB)
.withDefaultSizeOfMaxObjectGraph(2000)
.withCache(CACHE_NAME_CHINESE_DIC, cacheConfiguration)
.withCache(CACHE_NAME_ENGLISH_DIC, cacheConfiguration)
.build(true);
重要的几个知识点:
ehcache是分层缓存的
heap 堆内缓存,也就是存储在JVM内存中;
off heap 堆外缓存,非JVM单独非配的一部分内存。因此,设置的参数要与jvm启动参数相协调。
disk 磁盘缓存,也就是将缓存内容写入到磁盘文件中。
cluster 集群缓存,它是需要已cluster服务器来处同步存储这些数据。
注意:
1.heap是必须配置的;
2.disk tier不能与cluster tier共存,因为,它们回产生不一致;
3.个缓存tier是金字塔的配置,也就是 heap > off heap > disk > cluster,并且配置的大小是一次递增。
4.除了heap tier之外,其它层都必须设置key和value的序列化器和反序列化器。另外基础数据类型,已经实现其对相应的序列化/反序列化器。
ResourcePoolsBuilder是每个cache独立的,它仅仅只是配置信息。如:如果配置heap=20M,那么每个cache都有20M.
过期时间设置策略
如:withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofHours(24))
no expiry 永不过期
time-to-live 从缓存开始计算,所存储的时间
time-to-idle 最后一次使用后计算,所存储的时间
UserManagedCache
一个功能不需要太全,但能满足基本的缓存,则使用此类。
UserManagedCache<Long, String> userManagedCache = UserManagedCacheBuilder.newUserManagedCacheBuilder(Long.class, String.class).build(false);
userManagedCache.init();
注:build(false)时,需要调用init()方法才有效。
此外,ehcache还有很多其他的设置,比如事务机制,集群,自定义线程池,自定义序列化器和反序列化器等等。在此就不在赘述,官网很详细。
springboot整合ehcache
由于版本的不同,之前的springboot集成的时3.0之前的jar, 但是从3.0之后,依赖地址有net.sfn.ehache.*改为org.apache.echache.*。因此,自己注入了sprintboot cacheManager的实现。
代码如下:
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.6.2</version>
</dependency>
@Configuration
@EnableCaching
public class CacheConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(CacheConfig.class);
private static final String CACHE_NAME_XXXX = "XXXX";
private static final String CACHE_NAME_YYYY = "YYYY";
@Bean
public CacheManager cacheManager() {
ResourcePoolsBuilder resourcePoolsBuilder = ResourcePoolsBuilder.newResourcePoolsBuilder().heap(20, MemoryUnit.MB).offheap(30, MemoryUnit.MB);
CacheConfiguration<String, Object> cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, Object.class, resourcePoolsBuilder)
.withValueSerializer(new PlainJavaSerializer<>(this.getClass().getClassLoader()))
.withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofHours(24))).build();
org.ehcache.CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.withDefaultSizeOfMaxObjectSize(500, MemoryUnit.KB)
.withDefaultSizeOfMaxObjectGraph(2000)
.withCache(CACHE_NAME_XXXX , cacheConfiguration)
.withCache(CACHE_NAME_YYYY, cacheConfiguration)
.build(true);
return new CacheManager() {
@Override
public Cache getCache(String name) {
org.ehcache.Cache<String, Object> heapEhcache = cacheManager.getCache(name, String.class, Object.class);
return new Cache() {
@Override
public String getName() {
return name;
}
@Override
public Object getNativeCache() {
return heapEhcache;
}
@Override
public ValueWrapper get(Object key) {
Object value = heapEhcache.get(String.valueOf(key));
return null == value ? null : () -> value;
}
@Override
public <T> T get(Object key, Class<T> type) {
Object value = heapEhcache.get(String.valueOf(key));
if (value != null && type != null && !type.isInstance(value)) {
throw new IllegalStateException("Cached value is not of required type [" + type.getName() + "]: " + value);
}
return (T) value;
}
@Override
public <T> T get(Object key, Callable<T> valueLoader) {
try {
return valueLoader.call();
} catch (Exception e) {
LOGGER.error("ehcache valueLoader.call occur error", e);
}
return null;
}
@Override
public void put(Object key, Object value) {
heapEhcache.put(String.valueOf(key), value);
}
@Override
public ValueWrapper putIfAbsent(Object key, Object value) {
Object putIfAbsent = heapEhcache.putIfAbsent(String.valueOf(key), value);
return putIfAbsent == null ? null : () -> putIfAbsent;
}
@Override
public void evict(Object key) {
heapEhcache.remove(String.valueOf(key));
}
@Override
public void clear() {
heapEhcache.clear();
}
};
}
@Override
public Collection<String> getCacheNames() {
String[] cacheNames = {CACHE_NAME_XXXX , CACHE_NAME_YYYY};
return Arrays.asList(cacheNames);
}
};
}
}
注意: 返回类型为ValueWrapper的Cache接口需要注意,源码提示:当返回为null说明缓存中没有此key,则直接返回null,然后就会从数据库中取数据。当有返回值时,说明缓存中有此key, 此时应该返回ValueWrapper的包裹类(包含了实际的返回值)。