Commit ab4a3aa5a16a124cf6f96ce237256958345d36de
1 parent
31c81ff7
#feat:增加CacheKeyGenerator
Showing
4 changed files
with
102 additions
and
28 deletions
README.md
pom.xml
src/main/java/com/irrigation/icl/cache/core/CustomCacheKeyGenerator.java
0 → 100644
| 1 | +package com.irrigation.icl.cache.core; | |
| 2 | + | |
| 3 | +import lombok.extern.slf4j.Slf4j; | |
| 4 | +import org.springframework.cache.interceptor.KeyGenerator; | |
| 5 | +import org.springframework.util.StringUtils; | |
| 6 | + | |
| 7 | +import java.lang.reflect.Method; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * @Author: boni | |
| 11 | + * @Date: 2018/9/4-下午3:20 | |
| 12 | + */ | |
| 13 | +@Slf4j | |
| 14 | +public class CustomCacheKeyGenerator implements KeyGenerator { | |
| 15 | + public static final int NO_PARAM_KEY = 0; | |
| 16 | + | |
| 17 | + @Override | |
| 18 | + public Object generate(Object target, Method method, Object... params) { | |
| 19 | + StringBuilder key = new StringBuilder(); | |
| 20 | + key.append(target.getClass().getSimpleName()).append(".").append(method.getName()).append(":"); | |
| 21 | + if (params.length == 0) { | |
| 22 | + return key.append(NO_PARAM_KEY).toString(); | |
| 23 | + } | |
| 24 | + key.append(StringUtils.arrayToCommaDelimitedString(params)); | |
| 25 | + //String finalKey = key.toString(); | |
| 26 | + //log.debug("using cache key={}", finalKey); | |
| 27 | + return key.toString(); | |
| 28 | + } | |
| 29 | +} | ... | ... |
src/main/java/com/irrigation/icl/cache/core/LayeringCache.java
| ... | ... | @@ -6,17 +6,18 @@ import net.sf.ehcache.CacheException; |
| 6 | 6 | import net.sf.ehcache.CacheManager; |
| 7 | 7 | import net.sf.ehcache.Ehcache; |
| 8 | 8 | import net.sf.ehcache.Element; |
| 9 | -import net.sf.ehcache.config.CacheConfiguration; | |
| 10 | -import net.sf.ehcache.config.Configuration; | |
| 11 | -import net.sf.ehcache.config.DiskStoreConfiguration; | |
| 12 | -import net.sf.ehcache.config.PersistenceConfiguration; | |
| 9 | +import net.sf.ehcache.config.*; | |
| 13 | 10 | import net.sf.ehcache.store.MemoryStoreEvictionPolicy; |
| 11 | +import net.sf.ehcache.store.compound.ReadWriteCopyStrategy; | |
| 14 | 12 | import org.springframework.cache.Cache; |
| 13 | +import org.springframework.cache.ehcache.EhCacheCacheManager; | |
| 14 | +import org.springframework.cache.ehcache.EhCacheManagerFactoryBean; | |
| 15 | 15 | import org.springframework.cache.support.SimpleValueWrapper; |
| 16 | 16 | import org.springframework.data.redis.cache.RedisCache; |
| 17 | 17 | import org.springframework.data.redis.core.RedisOperations; |
| 18 | 18 | import org.springframework.util.StopWatch; |
| 19 | 19 | |
| 20 | +import java.io.Serializable; | |
| 20 | 21 | import java.sql.Time; |
| 21 | 22 | import java.text.SimpleDateFormat; |
| 22 | 23 | import java.time.LocalDateTime; |
| ... | ... | @@ -83,7 +84,8 @@ public class LayeringCache extends RedisCache { |
| 83 | 84 | // 先更新1级然后再更新2级;允许短时间内的数据不一致 |
| 84 | 85 | if (layerL1Enable) { |
| 85 | 86 | Ehcache ehCache = getL1Cache(super.getName()); |
| 86 | - ehCache.put(new Element(key, value, false, layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds(), layeringCacheProperties.getCacheL1().getLocalTimeToLiveSeconds())); | |
| 87 | + ehCache.put(new Element(key, value, false, layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds(), layeringCacheProperties.getCacheL1() | |
| 88 | + .getLocalTimeToLiveSeconds())); | |
| 87 | 89 | layeringCacheManager.publishMessage(Command.set(this.ID, super.getName(), String.valueOf(key))); |
| 88 | 90 | } |
| 89 | 91 | super.put(key, value); |
| ... | ... | @@ -106,7 +108,8 @@ public class LayeringCache extends RedisCache { |
| 106 | 108 | public Cache.ValueWrapper putIfAbsent(Object key, final Object value) { |
| 107 | 109 | if (layerL1Enable) { |
| 108 | 110 | Ehcache ehCache = getL1Cache(super.getName()); |
| 109 | - ehCache.putIfAbsent(new Element(key, value, false, layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds(), layeringCacheProperties.getCacheL1().getLocalTimeToLiveSeconds())); | |
| 111 | + ehCache.putIfAbsent(new Element(key, value, false, layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds(), layeringCacheProperties | |
| 112 | + .getCacheL1().getLocalTimeToLiveSeconds())); | |
| 110 | 113 | layeringCacheManager.publishMessage(Command.set(this.ID, super.getName(), String.valueOf(key))); |
| 111 | 114 | } |
| 112 | 115 | Cache.ValueWrapper wrapper = super.putIfAbsent(key, value); |
| ... | ... | @@ -125,7 +128,8 @@ public class LayeringCache extends RedisCache { |
| 125 | 128 | Cache.ValueWrapper wrapper = super.get(command.getKey()); |
| 126 | 129 | if (wrapper != null) { |
| 127 | 130 | Ehcache ehCache = getL1Cache(super.getName()); |
| 128 | - ehCache.put(new Element(command.getKey(), wrapper.get(), false, layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds(), layeringCacheProperties.getCacheL1().getLocalTimeToLiveSeconds())); | |
| 131 | + ehCache.put(new Element(command.getKey(), wrapper.get(), false, layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds(), | |
| 132 | + layeringCacheProperties.getCacheL1().getLocalTimeToLiveSeconds())); | |
| 129 | 133 | log.info("Update Cache L1 {} - {}", command.getKey(), wrapper.get()); |
| 130 | 134 | } |
| 131 | 135 | break; |
| ... | ... | @@ -142,9 +146,12 @@ public class LayeringCache extends RedisCache { |
| 142 | 146 | Future<Ehcache> future = this.layeringL1CacheContainer.get(name); |
| 143 | 147 | if (future == null) { |
| 144 | 148 | Callable<Ehcache> callable = () -> { |
| 145 | - Ehcache cache = layeringL1CacheManager.getEhcache(name); | |
| 149 | + Ehcache cache = layeringL1CacheManager.getCache(name); | |
| 146 | 150 | if (cache == null) { |
| 147 | - layeringL1CacheManager.addCache(name); | |
| 151 | + CacheConfiguration cacheConfiguration = getCacheConfiguration(); | |
| 152 | + cacheConfiguration.setName(name); | |
| 153 | + Ehcache ehcache = new net.sf.ehcache.Cache(cacheConfiguration); | |
| 154 | + layeringL1CacheManager.addCache(ehcache); | |
| 148 | 155 | cache = layeringL1CacheManager.getEhcache(name); |
| 149 | 156 | } |
| 150 | 157 | return cache; |
| ... | ... | @@ -165,12 +172,42 @@ public class LayeringCache extends RedisCache { |
| 165 | 172 | |
| 166 | 173 | } |
| 167 | 174 | |
| 175 | + | |
| 168 | 176 | private String getDate() { |
| 169 | 177 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS"); |
| 170 | 178 | |
| 171 | 179 | return simpleDateFormat.format(new Date()); |
| 172 | 180 | } |
| 173 | 181 | |
| 182 | + private CacheConfiguration getCacheConfiguration() { | |
| 183 | + // Cache | |
| 184 | + CacheConfiguration cacheConfiguration = new CacheConfiguration(); | |
| 185 | + cacheConfiguration.setEternal(false); | |
| 186 | + | |
| 187 | + PersistenceConfiguration persistenceConfiguration = new PersistenceConfiguration(); | |
| 188 | + persistenceConfiguration.setStrategy(PersistenceConfiguration.Strategy.NONE.name()); | |
| 189 | + | |
| 190 | + cacheConfiguration.persistence(persistenceConfiguration); | |
| 191 | + cacheConfiguration.memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LRU); | |
| 192 | + cacheConfiguration.setDiskExpiryThreadIntervalSeconds(layeringCacheProperties.getCacheL1().getLocalDiskExpiryThreadIntervalSeconds()); | |
| 193 | + // 默认false,使用引用.设置为true,避免外部代码修改了缓存对象.造成EhCache的缓存对象也随之改变 | |
| 194 | + // 但是设置为true后,将引起element的tti不自动刷新.如果直接新建element去覆盖原值.则本地ttl和远程ttl会产生一定的误差. | |
| 195 | + // 因此,使用时放弃手动覆盖方式刷新本地tti,当本地tti过期后,自动从Redis中再获取即可. | |
| 196 | + cacheConfiguration.copyOnRead(true); | |
| 197 | + cacheConfiguration.copyOnWrite(true); | |
| 198 | + | |
| 199 | +// CopyStrategyConfiguration copyStrategyConfiguration = new CopyStrategyConfiguration(); | |
| 200 | +// copyStrategyConfiguration.setClass(MyCopyStrategy.class.getName()); | |
| 201 | +// copyStrategyConfiguration.setCopyStrategyInstance(new MyCopyStrategy()); | |
| 202 | + | |
| 203 | +// cacheConfiguration.addCopyStrategy(copyStrategyConfiguration); | |
| 204 | + | |
| 205 | + cacheConfiguration.setTimeToIdleSeconds(layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds()); | |
| 206 | + cacheConfiguration.setTimeToLiveSeconds(layeringCacheProperties.getCacheL1().getLocalTimeToLiveSeconds()); | |
| 207 | + | |
| 208 | + return cacheConfiguration; | |
| 209 | + } | |
| 210 | + | |
| 174 | 211 | private void initEhcache() { |
| 175 | 212 | if (layerL1Enable) { |
| 176 | 213 | this.ID = layeringCacheProperties.getCacheL1().getKey() + "." + getDate(); |
| ... | ... | @@ -192,30 +229,35 @@ public class LayeringCache extends RedisCache { |
| 192 | 229 | dsc.setPath(layeringCacheProperties.getCacheL1().getLocalStoreLocation() + this.ID); |
| 193 | 230 | configuration.diskStore(dsc); |
| 194 | 231 | |
| 195 | - PersistenceConfiguration persistenceConfiguration = new PersistenceConfiguration(); | |
| 196 | - persistenceConfiguration.setStrategy(PersistenceConfiguration.Strategy.NONE.name()); | |
| 197 | - | |
| 198 | - // Cache | |
| 199 | - CacheConfiguration cacheConfiguration = new CacheConfiguration(); | |
| 200 | - cacheConfiguration.setEternal(false); | |
| 201 | - | |
| 202 | - cacheConfiguration.persistence(persistenceConfiguration); | |
| 203 | - cacheConfiguration.memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LRU); | |
| 204 | - cacheConfiguration.setDiskExpiryThreadIntervalSeconds(layeringCacheProperties.getCacheL1().getLocalDiskExpiryThreadIntervalSeconds()); | |
| 205 | - // 默认false,使用引用.设置为true,避免外部代码修改了缓存对象.造成EhCache的缓存对象也随之改变 | |
| 206 | - // 但是设置为true后,将引起element的tti不自动刷新.如果直接新建element去覆盖原值.则本地ttl和远程ttl会产生一定的误差. | |
| 207 | - // 因此,使用时放弃手动覆盖方式刷新本地tti,当本地tti过期后,自动从Redis中再获取即可. | |
| 208 | - cacheConfiguration.copyOnRead(true); | |
| 209 | - cacheConfiguration.copyOnWrite(true); | |
| 210 | - | |
| 211 | - cacheConfiguration.setTimeToIdleSeconds(layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds()); | |
| 212 | - cacheConfiguration.setTimeToLiveSeconds(layeringCacheProperties.getCacheL1().getLocalTimeToLiveSeconds()); | |
| 232 | + CacheConfiguration cacheConfiguration = getCacheConfiguration(); | |
| 213 | 233 | |
| 214 | 234 | configuration.setDefaultCacheConfiguration(cacheConfiguration); |
| 215 | 235 | configuration.setDynamicConfig(false); |
| 216 | 236 | configuration.setUpdateCheck(false); |
| 217 | 237 | |
| 238 | + | |
| 218 | 239 | layeringL1CacheManager = new CacheManager(configuration); |
| 219 | 240 | } |
| 220 | 241 | } |
| 242 | + | |
| 243 | + class MyCopyStrategy implements ReadWriteCopyStrategy<Element> { | |
| 244 | + @Override | |
| 245 | + public Element copyForWrite(Element value) { | |
| 246 | + if (value != null) { | |
| 247 | + Object temp = (Serializable) value.getObjectValue(); | |
| 248 | + return new Element(value.getObjectKey(), temp); | |
| 249 | + } | |
| 250 | + return value; | |
| 251 | + } | |
| 252 | + | |
| 253 | + @Override | |
| 254 | + public Element copyForRead(Element storedValue) { | |
| 255 | + if (storedValue != null) { | |
| 256 | + Object temp = (Serializable) storedValue.getObjectValue(); | |
| 257 | + return new Element(storedValue.getObjectKey(), temp); | |
| 258 | + } | |
| 259 | + return storedValue; | |
| 260 | + | |
| 261 | + } | |
| 262 | + } | |
| 221 | 263 | } | ... | ... |