最近要使用EHCache3.8,网上的文档发现很少,多半都是2.x的,偶尔有些3.x的都是相互复制粘贴一些官网的.而使用JSR-107以Program方式配置的Blog一个都没看到,而且配置DISK 的Persistence 或者 Cluster的URI的也是一个都没有,只有自己手动去找和探索.所以呢总结下.
官方文档
Ehcache 3.8 https://www.ehcache.org/documentation/3.8/index.html
POM
首先是依赖的引入, cache-api 是 JSR-107 的依赖,2.x的ehcache是引入的 net.sf.ehcache ,而3.x则需要引入 org.ehcache , ehcache-clustered 则是集群所需要的依赖.
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache-clustered</artifactId>
</dependency>
Configuration
package com.ehc.generated.config;
import java.io.File;
import java.net.URI;
import java.time.Duration;
import javax.cache.CacheManager;
import javax.cache.Caching;
import javax.cache.spi.CachingProvider;
import com.ehc.generated.domain.User;
import org.ehcache.clustered.client.config.builders.ClusteredResourcePoolBuilder;
import org.ehcache.clustered.client.config.builders.ClusteringServiceConfigurationBuilder;
import org.ehcache.config.builders.*;
import org.ehcache.config.units.MemoryUnit;
import org.ehcache.core.config.DefaultConfiguration;
import org.ehcache.impl.config.persistence.DefaultPersistenceConfiguration;
import org.ehcache.jsr107.Eh107Configuration;
import org.hibernate.cache.jcache.ConfigSettings;
import org.ehcache.jsr107.EhcacheCachingProvider;
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.cache.jcache.JCacheCacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.*;
@Configuration
@EnableCaching
public class CacheConfiguration {
private final javax.cache.configuration.Configuration<String, User> jcacheConfiguration;
private JCacheCacheManager jCacheCacheManager;
public CacheConfiguration() {
jcacheConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration(CacheConfigurationBuilder
.newCacheConfigurationBuilder(String.class, User.class,
ResourcePoolsBuilder.heap(10)
// .disk(10, MemoryUnit.MB, true)
.with(ClusteredResourcePoolBuilder.clusteredShared("resource-pool-a")))
.withExpiry(
ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(3600)))
.build());
CachingProvider cachingProvider = Caching.getCachingProvider();
EhcacheCachingProvider ehcacheProvider = (EhcacheCachingProvider) cachingProvider;
DefaultConfiguration configuration = new DefaultConfiguration(ehcacheProvider.getDefaultClassLoader(),
// new DefaultPersistenceConfiguration(new File("D:/training/EHCache/cache")),
ClusteringServiceConfigurationBuilder.cluster(URI.create("terracotta://localhost:9410/clustered"))
.autoCreate(c -> c.defaultServerResource("default-resource").resourcePool("resource-pool-a", 10,
MemoryUnit.MB, "default-resource"))
.build());
CacheManager cacheManager = ehcacheProvider.getCacheManager(ehcacheProvider.getDefaultURI(), configuration);
createCache(cacheManager, com.ehc.generated.repository.UserRepository.USERS_BY_LOGIN_CACHE);
createCache(cacheManager, com.ehc.generated.repository.UserRepository.USERS_BY_EMAIL_CACHE);
jCacheCacheManager = new JCacheCacheManager(cacheManager);
}
@Bean
public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(CacheManager cacheManager) {
return hibernateProperties -> hibernateProperties.put(ConfigSettings.CACHE_MANAGER, cacheManager);
}
@Bean
public org.springframework.cache.CacheManager cacheManager() {
return jCacheCacheManager;
}
@Bean
public CacheManager cacheManagers() {
return jCacheCacheManager.getCacheManager();
}
private void createCache(javax.cache.CacheManager cm, String cacheName) {
javax.cache.Cache<Object, Object> cache = cm.getCache(cacheName);
if (cache == null) {
cm.createCache(cacheName, jcacheConfiguration);
}
}
}
首先,我是单独写的一个Configuration来配置Cache,我把disk的配置comment了,因为disk和cluster只能配置一个,不能同时配置.我一开始配置的时候忘记了,启动的时候一直报错,突然想起来才comment掉了disk.
这里我配置了一个heap层一个cluster层.
还需要注意一点就是,heap层不需要序列化和反序列化,所以,当只配置heap层时,不需要序列化(因为heap是默认用 by-reference.当然也可以用 copiers 来设置,就是实现Copier的接口,让他用key-value的形式),但是一旦配置了除开heap的其他层(例如 offheap,disk,cluster),这时候的key和value必须时可序列化的,否则就会报错.
这是除了cluster的其他3个层的简介.
jcacheConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration(CacheConfigurationBuilder
.newCacheConfigurationBuilder(String.class, User.class,
ResourcePoolsBuilder.heap(10)
// .disk(10, MemoryUnit.MB, true)
.with(ClusteredResourcePoolBuilder.clusteredShared("resource-pool-a")))
.withExpiry(
ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(3600)))
.build());
这段代码是对每个Name的Cache的通用配置,当然你也可以每个Name的Cache单独进行配置,我只是为了方便演示做的同一配置. 我这里配置了heap层可以容纳10条缓存,cluster 使用 resource-pool-a这个shared池 (当其他集群中的inst也使用这个share池时,就相当于共享缓存了,虽然文档上的解释是他们依然是相互独立的,只不过是底层储存共享了,但是你也可以直接理解成共享),还配置了TTL,一小时后超时.
重点
这之前的配置在其他文档或者很多Blog中都可以查到,但是之后的配置让我头疼了很久,所有Blog中都没有关于cacheManager层的配置.
PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.with(CacheManagerBuilder.persistence(new File(getStoragePath(), "myData")))
.withCache("persistent-cache", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder().disk(10, MemoryUnit.MB, true))
)
.build(true);
因为在文档中,对与cacheMannager层的配置,都是使用CacheManagerBuilder在build之前使用with进行配置,比如上面的代码,配置了disk 的持久化文件目录.
CachingProvider provider = Caching.getCachingProvider();
CacheManager cacheManager = provider.getCacheManager();
然而JSR-107的cacheManager是直接从cacheProvider中直接get出来的,这个配置到底怎么放进去? 这个问题我都快把搜索引擎搜烂了都没有找到. stackoverflow 提问题也没人回答.
直到后来在文档中,刚好有小小的一段提到了这个.结束了我头痛的路程.
CachingProvider cachingProvider = Caching.getCachingProvider();
EhcacheCachingProvider ehcacheProvider = (EhcacheCachingProvider) cachingProvider;
DefaultConfiguration configuration = new DefaultConfiguration(ehcacheProvider.getDefaultClassLoader(),
// new DefaultPersistenceConfiguration(new File("D:/training/EHCache/cache")),
ClusteringServiceConfigurationBuilder.cluster(URI.create("terracotta://localhost:9410/clustered"))
.autoCreate(c -> c.defaultServerResource("default-resource").resourcePool("resource-pool-a", 10,
MemoryUnit.MB, "default-resource"))
.build());
CacheManager cacheManager = ehcacheProvider.getCacheManager(ehcacheProvider.getDefaultURI(), configuration);
我们看DefaultConfiguration的源码,它可以支持多个配置,如果disk和cluster可以同时配置的话,就直接可以把我comment的代码打开就行了,配置了cluster的 默认资源,以及给stare池分配10M的空间,以及配置disk持久化目录 .
.disk(10, MemoryUnit.MB, true)
这里需要注意的一点是,disk方法的第三个参数可配可不配,如果不配默认为false,代表不会持久化,JVM启动时,cache会写入配置的持久化目录,当JVM停止时,它会把它莫除掉,如果配置了true,才会真正的持久化,JVM停止时不会抹除,第二次重新启动时回去加载它.
这是集群中,一些关键词的解释.
还有一个点就是定义了两个,CacheManger的bean.原因是JSR-107需要一个 javax.cache.CacheManager , 而Spring-Boot-Cache 则需要一个 org.springframework.cache.CacheManager 的bean.
Terracotta Server Deploy
https://github.com/ehcache/ehcache3/releases
我是win10环境,就下的ZIP.
它的配置文件默认在server/conf下
启动的batch/shell默认在server/bin下,这里面的tc-config.xml默认时没有的,这是我放进去的.
配置了一个名叫default-resource的offheap的资源.启动在9410, URI为 terracotta://localhost:9410/clustered
<?xml version="1.0" encoding="UTF-8" ?>
<tc-config xmlns="http://www.terracotta.org/config"
xmlns:ohr="http://www.terracotta.org/config/offheap-resource"
xmlns:data="http://www.terracottatech.com/config/data-roots"
xmlns:persistence="http://www.terracottatech.com/config/platform-persistence">
<plugins>
<config>
<ohr:offheap-resources>
<ohr:resource name="default-resource" unit="MB">512</ohr:resource>
</ohr:offheap-resources>
</config>
</plugins>
<servers>
<server host="localhost" name="clustered">
<tsa-port>9410</tsa-port>
<logs>terracotta/server-logs</logs>
</server>
</servers>
<failover-priority>
<availability/>
</failover-priority>
</tc-config>
start-tc-server.bat ./tc-config.xml 强制使用当前目录的config.xml跑start的bat,当看到红线的一段话,代表Terracotta Server启动成功了.
这时候再去启动项目,看到这个表示集群链接成功