當咱們使用hibernate-ehcache包(Ehcache 2)做爲hibernate二級緩存時,系統會提示警告說已通過時了,那這時候找到spring boot推薦的新的二級緩存方案,如今推薦hibernate-jcache,能夠與Ehcache 3或是其餘實現了javax.cache.spi.CachingProvider的緩存自動集成java
jcache是一種緩存門面規範,並不包含具體緩存實現,spring boot推薦與jcache搭配使用的是Hazelcast,Hazelcast實現了CachingProvider,能夠直接做爲hibernate二級緩存,Hazelcast實現下一篇再提供git
hibernate二級緩存重構以後,要本身實現也很是簡單,只須要實現github
org.hibernate.cache.spi.support.RegionFactoryTemplatespring
org.hibernate.cache.spi.support.DomainDataStorageAccessapache
這兩個類就能夠了,引入caffeine包緩存
<dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> </dependency>
下面是DomainDataStorageAccess實現,這個類就是緩存操做的實現springboot
import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.StringUtils; import org.hibernate.cache.spi.support.DomainDataStorageAccess; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import lombok.NonNull; public class CaffeineDataRegion implements DomainDataStorageAccess { protected final Logger log = LoggerFactory.getLogger(this.getClass()); /** * Region regionName */ private final String regionName; private final Cache<Object, Object> cache; private final int expiryInSeconds; // seconds static final int DEFAULT_EXPIRY_IN_SECONDS = 1800; public CaffeineDataRegion(@NonNull String regionName) { this.regionName = StringUtils.replace(regionName, ".", ":") + ":"; this.expiryInSeconds = DEFAULT_EXPIRY_IN_SECONDS; cache = Caffeine.newBuilder() // 設置cache中的數據在寫入以後的存活時間 .expireAfterWrite(30, TimeUnit.MINUTES) // 構建cache實例 .build(); log.debug("caffeiene region={}, expiryInSeconds={}", regionName, expiryInSeconds); } /** * confirm the specified key exists in current region * * @param key * cache key * @return if cache key is exists in current region return true, else return * false */ @Override public boolean contains(Object key) { try { log.debug("contains key={}", key); return cache.getIfPresent(key) != null; } catch (Exception ignored) { log.warn("Fail to exists key. key=" + key, ignored); return false; } } @Override public Object getFromCache(Object key, SharedSessionContractImplementor session) { try { return cache.getIfPresent(key); } catch (Exception ignored) { log.warn("Fail to get cache item... key=" + key, ignored); return null; } } @Override public void putIntoCache(Object key, Object value, SharedSessionContractImplementor session) { try { cache.put(key, value); } catch (Exception ignored) { log.warn("Fail to put cache item... key=" + key, ignored); } } @Override public void evictData() { try { cache.invalidateAll(); } catch (Exception ignored) { log.warn("Fail to clear region... name=" + regionName, ignored); } } @Override public void evictData(Object key) { try { cache.invalidate(key); } catch (Exception ignored) { log.warn("Fail to remove cache item... key=" + key, ignored); } } @Override public void release() { } }
下面是RegionFactoryTemplate實現,這個類是緩存啓動類session
import java.util.Map; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.cache.cfg.spi.DomainDataRegionBuildingContext; import org.hibernate.cache.cfg.spi.DomainDataRegionConfig; import org.hibernate.cache.spi.support.DomainDataStorageAccess; import org.hibernate.cache.spi.support.RegionFactoryTemplate; import org.hibernate.cache.spi.support.StorageAccess; import org.hibernate.engine.spi.SessionFactoryImplementor; import com.bc.plugin.caffeine.hibernate.regions.CaffeineDataRegion; import lombok.extern.slf4j.Slf4j; @Slf4j public class CaffeineRegionFactory extends RegionFactoryTemplate { private static final long serialVersionUID = 1L; @Override protected StorageAccess createQueryResultsRegionStorageAccess(String regionName, SessionFactoryImplementor sessionFactory) { return new CaffeineDataRegion(regionName); } @Override protected StorageAccess createTimestampsRegionStorageAccess(String regionName, SessionFactoryImplementor sessionFactory) { return new CaffeineDataRegion(regionName); } @Override protected DomainDataStorageAccess createDomainDataStorageAccess(DomainDataRegionConfig regionConfig, DomainDataRegionBuildingContext buildingContext) { return new CaffeineDataRegion(regionConfig.getRegionName()); } @Override protected void prepareForUse(SessionFactoryOptions settings, @SuppressWarnings("rawtypes") Map configValues) { log.debug("RegionFactory is starting... options={}, properties={}", settings, configValues); } @Override protected void releaseFromUse() { } }
而後配置spring.jpa.properties.hibernate.cache.region.factory_class=/*org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory */ide
org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory是hibernate-ehcache包中的實現,ui
替換成咱們CaffeineRegionFactory類的全路徑就能夠了
引入caffeine包後,spring cache也會使用caffeine,springboot會自動配置caffeine