From ab4a3aa5a16a124cf6f96ce237256958345d36de Mon Sep 17 00:00:00 2001 From: boni Date: Wed, 5 Sep 2018 15:14:02 +0800 Subject: [PATCH] #feat:增加CacheKeyGenerator --- README.md | 3 +++ pom.xml | 2 +- src/main/java/com/irrigation/icl/cache/core/CustomCacheKeyGenerator.java | 29 +++++++++++++++++++++++++++++ src/main/java/com/irrigation/icl/cache/core/LayeringCache.java | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------- 4 files changed, 102 insertions(+), 28 deletions(-) create mode 100644 src/main/java/com/irrigation/icl/cache/core/CustomCacheKeyGenerator.java diff --git a/README.md b/README.md index 0634140..55fed43 100644 --- a/README.md +++ b/README.md @@ -24,3 +24,6 @@ spring: pool: max-wait: 1 ``` + +### v1.2.1 +- 增加了KeyGenerator实现类,实现类中使用className.methodName:params拼接成key diff --git a/pom.xml b/pom.xml index b942a7d..1008cb4 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.irrigation common-lib - 1.2.0 + 1.2.1 UTF-8 diff --git a/src/main/java/com/irrigation/icl/cache/core/CustomCacheKeyGenerator.java b/src/main/java/com/irrigation/icl/cache/core/CustomCacheKeyGenerator.java new file mode 100644 index 0000000..55120ad --- /dev/null +++ b/src/main/java/com/irrigation/icl/cache/core/CustomCacheKeyGenerator.java @@ -0,0 +1,29 @@ +package com.irrigation.icl.cache.core; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.interceptor.KeyGenerator; +import org.springframework.util.StringUtils; + +import java.lang.reflect.Method; + +/** + * @Author: boni + * @Date: 2018/9/4-下午3:20 + */ +@Slf4j +public class CustomCacheKeyGenerator implements KeyGenerator { + public static final int NO_PARAM_KEY = 0; + + @Override + public Object generate(Object target, Method method, Object... params) { + StringBuilder key = new StringBuilder(); + key.append(target.getClass().getSimpleName()).append(".").append(method.getName()).append(":"); + if (params.length == 0) { + return key.append(NO_PARAM_KEY).toString(); + } + key.append(StringUtils.arrayToCommaDelimitedString(params)); + //String finalKey = key.toString(); + //log.debug("using cache key={}", finalKey); + return key.toString(); + } +} diff --git a/src/main/java/com/irrigation/icl/cache/core/LayeringCache.java b/src/main/java/com/irrigation/icl/cache/core/LayeringCache.java index f9886b6..4d0d580 100644 --- a/src/main/java/com/irrigation/icl/cache/core/LayeringCache.java +++ b/src/main/java/com/irrigation/icl/cache/core/LayeringCache.java @@ -6,17 +6,18 @@ import net.sf.ehcache.CacheException; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Ehcache; import net.sf.ehcache.Element; -import net.sf.ehcache.config.CacheConfiguration; -import net.sf.ehcache.config.Configuration; -import net.sf.ehcache.config.DiskStoreConfiguration; -import net.sf.ehcache.config.PersistenceConfiguration; +import net.sf.ehcache.config.*; import net.sf.ehcache.store.MemoryStoreEvictionPolicy; +import net.sf.ehcache.store.compound.ReadWriteCopyStrategy; import org.springframework.cache.Cache; +import org.springframework.cache.ehcache.EhCacheCacheManager; +import org.springframework.cache.ehcache.EhCacheManagerFactoryBean; import org.springframework.cache.support.SimpleValueWrapper; import org.springframework.data.redis.cache.RedisCache; import org.springframework.data.redis.core.RedisOperations; import org.springframework.util.StopWatch; +import java.io.Serializable; import java.sql.Time; import java.text.SimpleDateFormat; import java.time.LocalDateTime; @@ -83,7 +84,8 @@ public class LayeringCache extends RedisCache { // 先更新1级然后再更新2级;允许短时间内的数据不一致 if (layerL1Enable) { Ehcache ehCache = getL1Cache(super.getName()); - ehCache.put(new Element(key, value, false, layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds(), layeringCacheProperties.getCacheL1().getLocalTimeToLiveSeconds())); + ehCache.put(new Element(key, value, false, layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds(), layeringCacheProperties.getCacheL1() + .getLocalTimeToLiveSeconds())); layeringCacheManager.publishMessage(Command.set(this.ID, super.getName(), String.valueOf(key))); } super.put(key, value); @@ -106,7 +108,8 @@ public class LayeringCache extends RedisCache { public Cache.ValueWrapper putIfAbsent(Object key, final Object value) { if (layerL1Enable) { Ehcache ehCache = getL1Cache(super.getName()); - ehCache.putIfAbsent(new Element(key, value, false, layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds(), layeringCacheProperties.getCacheL1().getLocalTimeToLiveSeconds())); + ehCache.putIfAbsent(new Element(key, value, false, layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds(), layeringCacheProperties + .getCacheL1().getLocalTimeToLiveSeconds())); layeringCacheManager.publishMessage(Command.set(this.ID, super.getName(), String.valueOf(key))); } Cache.ValueWrapper wrapper = super.putIfAbsent(key, value); @@ -125,7 +128,8 @@ public class LayeringCache extends RedisCache { Cache.ValueWrapper wrapper = super.get(command.getKey()); if (wrapper != null) { Ehcache ehCache = getL1Cache(super.getName()); - ehCache.put(new Element(command.getKey(), wrapper.get(), false, layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds(), layeringCacheProperties.getCacheL1().getLocalTimeToLiveSeconds())); + ehCache.put(new Element(command.getKey(), wrapper.get(), false, layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds(), + layeringCacheProperties.getCacheL1().getLocalTimeToLiveSeconds())); log.info("Update Cache L1 {} - {}", command.getKey(), wrapper.get()); } break; @@ -142,9 +146,12 @@ public class LayeringCache extends RedisCache { Future future = this.layeringL1CacheContainer.get(name); if (future == null) { Callable callable = () -> { - Ehcache cache = layeringL1CacheManager.getEhcache(name); + Ehcache cache = layeringL1CacheManager.getCache(name); if (cache == null) { - layeringL1CacheManager.addCache(name); + CacheConfiguration cacheConfiguration = getCacheConfiguration(); + cacheConfiguration.setName(name); + Ehcache ehcache = new net.sf.ehcache.Cache(cacheConfiguration); + layeringL1CacheManager.addCache(ehcache); cache = layeringL1CacheManager.getEhcache(name); } return cache; @@ -165,12 +172,42 @@ public class LayeringCache extends RedisCache { } + private String getDate() { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS"); return simpleDateFormat.format(new Date()); } + private CacheConfiguration getCacheConfiguration() { + // Cache + CacheConfiguration cacheConfiguration = new CacheConfiguration(); + cacheConfiguration.setEternal(false); + + PersistenceConfiguration persistenceConfiguration = new PersistenceConfiguration(); + persistenceConfiguration.setStrategy(PersistenceConfiguration.Strategy.NONE.name()); + + cacheConfiguration.persistence(persistenceConfiguration); + cacheConfiguration.memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LRU); + cacheConfiguration.setDiskExpiryThreadIntervalSeconds(layeringCacheProperties.getCacheL1().getLocalDiskExpiryThreadIntervalSeconds()); + // 默认false,使用引用.设置为true,避免外部代码修改了缓存对象.造成EhCache的缓存对象也随之改变 + // 但是设置为true后,将引起element的tti不自动刷新.如果直接新建element去覆盖原值.则本地ttl和远程ttl会产生一定的误差. + // 因此,使用时放弃手动覆盖方式刷新本地tti,当本地tti过期后,自动从Redis中再获取即可. + cacheConfiguration.copyOnRead(true); + cacheConfiguration.copyOnWrite(true); + +// CopyStrategyConfiguration copyStrategyConfiguration = new CopyStrategyConfiguration(); +// copyStrategyConfiguration.setClass(MyCopyStrategy.class.getName()); +// copyStrategyConfiguration.setCopyStrategyInstance(new MyCopyStrategy()); + +// cacheConfiguration.addCopyStrategy(copyStrategyConfiguration); + + cacheConfiguration.setTimeToIdleSeconds(layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds()); + cacheConfiguration.setTimeToLiveSeconds(layeringCacheProperties.getCacheL1().getLocalTimeToLiveSeconds()); + + return cacheConfiguration; + } + private void initEhcache() { if (layerL1Enable) { this.ID = layeringCacheProperties.getCacheL1().getKey() + "." + getDate(); @@ -192,30 +229,35 @@ public class LayeringCache extends RedisCache { dsc.setPath(layeringCacheProperties.getCacheL1().getLocalStoreLocation() + this.ID); configuration.diskStore(dsc); - PersistenceConfiguration persistenceConfiguration = new PersistenceConfiguration(); - persistenceConfiguration.setStrategy(PersistenceConfiguration.Strategy.NONE.name()); - - // Cache - CacheConfiguration cacheConfiguration = new CacheConfiguration(); - cacheConfiguration.setEternal(false); - - cacheConfiguration.persistence(persistenceConfiguration); - cacheConfiguration.memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LRU); - cacheConfiguration.setDiskExpiryThreadIntervalSeconds(layeringCacheProperties.getCacheL1().getLocalDiskExpiryThreadIntervalSeconds()); - // 默认false,使用引用.设置为true,避免外部代码修改了缓存对象.造成EhCache的缓存对象也随之改变 - // 但是设置为true后,将引起element的tti不自动刷新.如果直接新建element去覆盖原值.则本地ttl和远程ttl会产生一定的误差. - // 因此,使用时放弃手动覆盖方式刷新本地tti,当本地tti过期后,自动从Redis中再获取即可. - cacheConfiguration.copyOnRead(true); - cacheConfiguration.copyOnWrite(true); - - cacheConfiguration.setTimeToIdleSeconds(layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds()); - cacheConfiguration.setTimeToLiveSeconds(layeringCacheProperties.getCacheL1().getLocalTimeToLiveSeconds()); + CacheConfiguration cacheConfiguration = getCacheConfiguration(); configuration.setDefaultCacheConfiguration(cacheConfiguration); configuration.setDynamicConfig(false); configuration.setUpdateCheck(false); + layeringL1CacheManager = new CacheManager(configuration); } } + + class MyCopyStrategy implements ReadWriteCopyStrategy { + @Override + public Element copyForWrite(Element value) { + if (value != null) { + Object temp = (Serializable) value.getObjectValue(); + return new Element(value.getObjectKey(), temp); + } + return value; + } + + @Override + public Element copyForRead(Element storedValue) { + if (storedValue != null) { + Object temp = (Serializable) storedValue.getObjectValue(); + return new Element(storedValue.getObjectKey(), temp); + } + return storedValue; + + } + } } -- libgit2 0.21.4