提交 a08ca6f5 编写于 作者: ibizdev's avatar ibizdev

zhouweidong@lab.ibiz5.com 发布系统代码

上级 80c78419
package cn.ibizlab.util.cache.layering;
import cn.ibizlab.util.enums.RedisChannelTopic;
import cn.ibizlab.util.cache.listener.RedisPublisher;
import cn.ibizlab.util.cache.redis.CustomizedRedisCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.AbstractValueAdaptingCache;
import org.springframework.cache.support.NullValue;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.core.RedisOperations;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* 缓存分层类
* 1级缓存为caffeine
* 2级缓存为redis
*/
public class LayeringCache extends AbstractValueAdaptingCache {
Logger logger = LoggerFactory.getLogger(LayeringCache.class);
public class LayeringCache {
/**
* 缓存的名称
*/
private final String name;
/**
* 是否使用一级缓存
*/
private boolean usedFirstCache = true;
/**
* redi缓存
*/
private RedisCache redisCache;
/**
* Caffeine缓存
*/
private final CaffeineCache caffeineCache;
RedisOperations<? extends Object, ? extends Object> redisOperations;
/**
* @param name 缓存名称
* @param allowNullValues 是否允许存NULL,默认是false
* @param usedFirstCache 是否使用一级缓存,默认是true
* @param caffeineCache Caffeine缓存
*/
public LayeringCache(String name , boolean allowNullValues,RedisOperations redisOperations, boolean usedFirstCache, com.github.benmanes.caffeine.cache.Cache<Object, Object> caffeineCache,
RedisCacheWriter redisCacheWriter, RedisCacheConfiguration configuration) {
super(allowNullValues);
this.name = name;
this.usedFirstCache = usedFirstCache;
this.redisCache = new CustomizedRedisCache(name, redisCacheWriter, configuration);
this.caffeineCache = new CaffeineCache(name, caffeineCache, allowNullValues);
this.redisOperations=redisOperations;
}
public CaffeineCache getFirstCache() {
return this.caffeineCache;
}
@Override
public String getName() {
return this.name;
}
@Override
public Object getNativeCache() {
return this;
}
@Override
public ValueWrapper get(Object key) {
ValueWrapper wrapper = null;
if (usedFirstCache) {
// 查询一级缓存
wrapper = caffeineCache.get(key);
logger.debug("查询一级缓存 key:{},value:{}", key,wrapper);
}
if (wrapper == null) {
// 查询二级缓存
wrapper = redisCache.get(key);
caffeineCache.put(key, wrapper == null ? null : wrapper.get());
logger.debug("查询二级缓存,并将数据放到一级缓存。 key:{}", key);
}
return wrapper;
}
@Override
public <T> T get(Object key, Class<T> type) {
T value = null;
if (usedFirstCache) {
// 查询一级缓存
value = caffeineCache.get(key, type);
logger.debug("查询一级缓存 key:{}", key);
}
if (value == null) {
// 查询二级缓存
value = redisCache.get(key, type);
caffeineCache.put(key, value);
logger.debug("查询二级缓存,并将数据放到一级缓存。 key:{}", key);
}
return value;
}
@SuppressWarnings("unchecked")
@Override
public <T> T get(Object key, Callable<T> valueLoader) {
T value = null;
if (usedFirstCache) {
// 查询一级缓存,如果一级缓存没有值则调用getForSecondaryCache(k, valueLoader)查询二级缓存
value = (T) caffeineCache.getNativeCache().get(key, k -> getForSecondaryCache(k, valueLoader));
} else {
// 直接查询二级缓存
value = (T) getForSecondaryCache(key, valueLoader);
}
if (value instanceof NullValue) {
return null;
}
return value;
}
@Override
public void put(Object key, Object value) {
if (usedFirstCache) {
caffeineCache.put(key, value);
}
redisCache.put(key, value);
}
@Override
public ValueWrapper putIfAbsent(Object key, Object value) {
if (usedFirstCache) {
caffeineCache.putIfAbsent(key, value);
}
return redisCache.putIfAbsent(key, value);
}
@Override
public void evict(Object key) {
redisCache.evict(key); //清除redis中的二级缓存
if (usedFirstCache) {
caffeineCache.evict(key);//清除本机一级缓存
Map<String, Object> message = new HashMap<>();
message.put("cacheName", name);
message.put("key", key);
RedisPublisher redisPublisher = new RedisPublisher(redisOperations, RedisChannelTopic.REDIS_CACHE_DELETE_TOPIC.getChannelTopic());// 创建redis发布者
redisPublisher.publisher(message);//发布消息,清除其它集群机器中的一级缓存
}
logger.debug(String.format("清除二级缓存数据[%s]", key));
}
@Override
public void clear() {
redisCache.clear(); //清除redis中的二级缓存
if (usedFirstCache) {
caffeineCache.clear();//清除本机一级缓存
Map<String, Object> message = new HashMap<>();
message.put("cacheName", name);
RedisPublisher redisPublisher = new RedisPublisher(redisOperations, RedisChannelTopic.REDIS_CACHE_CLEAR_TOPIC.getChannelTopic());// 创建redis发布者
redisPublisher.publisher(message);//发布消息,清除其它集群机器中的一级缓存
}
}
@Override
protected Object lookup(Object key) {
Object value = null;
if (usedFirstCache) {
value = caffeineCache.get(key);
logger.debug("查询一级缓存 key:{}", key);
}
if (value == null) {
value = redisCache.get(key);
logger.debug("查询二级缓存 key:{}", key);
}
return value;
}
/**
* 查询二级缓存
* @param key
* @param valueLoader
* @return
*/
private <T> Object getForSecondaryCache(Object key, Callable<T> valueLoader) {
T value = redisCache.get(key, valueLoader);
logger.debug("查询二级缓存 key:{}", key);
return toStoreValue(value);
}
}
package cn.ibizlab.util.cache.layering;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.CaffeineSpec;
import cn.ibizlab.util.cache.setting.FirstCacheSetting;
import cn.ibizlab.util.cache.setting.SecondaryCacheSetting;
import lombok.Data;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import org.springframework.util.StringUtils;
public class LayeringCacheManager {
/**
* 缓存分层类
* 1级缓存为caffeine
* 2级缓存为redis
*/
@Data
public class LayeringCacheManager implements CacheManager {
static final int DEFAULT_EXPIRE_AFTER_WRITE = 2;
static final int DEFAULT_INITIAL_CAPACITY = 5;
static final int DEFAULT_MAXIMUM_SIZE = 1_000;
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>(16);
/**
* 一级缓存配置
*/
private Map<String, FirstCacheSetting> firstCacheSettings = null;
/**
* 二级缓存配置
*/
private Map<String, SecondaryCacheSetting> secondaryCacheSettings = null;
public RedisCacheWriter redisCacheWriter;
public RedisCacheConfiguration redisConfiguration;
public RedisOperations redisOperations;
/**
* 是否允许动态创建缓存,默认是true
*/
private boolean dynamic = true;
/**
* 缓存值是否允许为NULL
*/
private boolean allowNullValues = false;
/**
* expireAfterWrite:2 小时
* initialCapacity:5
* maximumSize: 1_000
*/
private Caffeine<Object, Object> cacheBuilder = Caffeine.newBuilder()
.expireAfterAccess(DEFAULT_EXPIRE_AFTER_WRITE, TimeUnit.HOURS)
.initialCapacity(DEFAULT_INITIAL_CAPACITY)
.maximumSize(DEFAULT_MAXIMUM_SIZE);
public LayeringCacheManager(RedisTemplate<String, Object> redisTemplate) {
this.redisOperations=redisTemplate;
}
/**
* 获取缓存对象
* @param name
* @return
*/
@Override
public Cache getCache(String name) {
Cache cache = this.cacheMap.get(name);
if (cache == null && this.dynamic) {
synchronized (this.cacheMap) {
cache = this.cacheMap.get(name);
if (cache == null) {
cache = createCache(name);
this.cacheMap.put(name, cache);
}
}
}
return cache;
}
@Override
public Collection<String> getCacheNames() {
return Collections.unmodifiableSet(this.cacheMap.keySet());
}
protected Cache createCache(String name) {
return new LayeringCache(name,isAllowNullValues(),this.redisOperations, getUsedFirstCache(name),createNativeCaffeineCache(name),redisCacheWriter,redisConfiguration);
}
/**
* Create a native Caffeine Cache instance for the specified cache name.
*
* @param name the name of the cache
* @return the native Caffeine Cache instance
*/
protected com.github.benmanes.caffeine.cache.Cache<Object, Object> createNativeCaffeineCache(String name) {
return getCaffeine(name).build();
}
/**
* 使用该CacheManager的当前状态重新创建已知的缓存。
*/
private void refreshKnownCaches() {
for (Map.Entry<String, Cache> entry : this.cacheMap.entrySet()) {
entry.setValue(createCache(entry.getKey()));
}
}
/**
* 设置是否允许Cache的值为null
*
* @param allowNullValues
*/
public void setAllowNullValues(boolean allowNullValues) {
if (this.allowNullValues != allowNullValues) {
this.allowNullValues = allowNullValues;
refreshKnownCaches();
}
}
/**
* 获取是否允许Cache的值为null
*
* @return
*/
public boolean isAllowNullValues() {
return this.allowNullValues;
}
/**
* 根据缓存名称设置一级缓存的有效时间和刷新时间,单位秒
*
* @param firstCacheSettings
*/
public void setFirstCacheSettings(Map<String, FirstCacheSetting> firstCacheSettings) {
this.firstCacheSettings = (!CollectionUtils.isEmpty(firstCacheSettings) ? new ConcurrentHashMap<>(firstCacheSettings) : null);
}
/**
* 获取是否使用一级缓存,默认是true
*/
public boolean getUsedFirstCache(String name) {
SecondaryCacheSetting secondaryCacheSetting = null;
if (!CollectionUtils.isEmpty(secondaryCacheSettings)) {
secondaryCacheSetting = secondaryCacheSettings.get(name);
}
return secondaryCacheSetting != null ? secondaryCacheSetting.getUsedFirstCache() : true;
}
public void setCaffeineSpec(CaffeineSpec caffeineSpec) {
Caffeine<Object, Object> cacheBuilder = Caffeine.from(caffeineSpec);
if (!ObjectUtils.nullSafeEquals(this.cacheBuilder, cacheBuilder)) {
this.cacheBuilder = cacheBuilder;
refreshKnownCaches();
}
}
private Caffeine<Object, Object> getCaffeine(String name) {
if (!CollectionUtils.isEmpty(firstCacheSettings)) {
FirstCacheSetting firstCacheSetting = firstCacheSettings.get(name);
if (firstCacheSetting != null && StringUtils.isEmpty(firstCacheSetting.getCacheSpecification())) {
// 根据缓存名称获取一级缓存配置
return Caffeine.from(CaffeineSpec.parse(firstCacheSetting.getCacheSpecification()));
}
}
return this.cacheBuilder;
}
}
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册