提交 9d3aa398 编写于 作者: zhouweidong's avatar zhouweidong

补充缓存开关

上级 575fcb58
<#ibiztemplate>
TARGET=PSSYSTEM
</#ibiztemplate>
package ${pub.getPKGCodeName()}.util.cache;
import com.github.benmanes.caffeine.cache.CaffeineSpec;
import ${pub.getPKGCodeName()}.util.cache.cacheManager.CaffeineCacheManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.util.StringUtils;
/**
* Caffeine缓存配置类
*/
@EnableCaching
@Configuration
@EnableConfigurationProperties(CacheProperties.class)
@ConditionalOnProperty("ibiz.enableCaffeineCache")
public class CaffeineCacheConfig {
@Autowired
private CacheProperties cacheProperties;
@Autowired
private CaffeineCacheManager caffeineCacheManager;
@Bean
@Primary
public CacheManager cacheManager() {
String specification = cacheProperties.getCaffeine().getSpec();
if (StringUtils.hasText(specification)) {
caffeineCacheManager.setCaffeineSpec(CaffeineSpec.parse(specification));
}
return caffeineCacheManager;
}
}
\ No newline at end of file
...@@ -8,15 +8,16 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect; ...@@ -8,15 +8,16 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.benmanes.caffeine.cache.CaffeineSpec; import com.github.benmanes.caffeine.cache.CaffeineSpec;
import ${pub.getPKGCodeName()}.util.enums.RedisChannelTopic; import ${pub.getPKGCodeName()}.util.cache.cacheManager.LayeringCacheManager;
import ${pub.getPKGCodeName()}.util.cache.layering.LayeringCacheManager;
import ${pub.getPKGCodeName()}.util.cache.redis.KryoRedisSerializer; import ${pub.getPKGCodeName()}.util.cache.redis.KryoRedisSerializer;
import ${pub.getPKGCodeName()}.util.cache.redis.StringRedisSerializer; import ${pub.getPKGCodeName()}.util.cache.redis.StringRedisSerializer;
import ${pub.getPKGCodeName()}.util.cache.setting.FirstCacheSetting; import ${pub.getPKGCodeName()}.util.enums.RedisChannelTopic;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.cache.CacheProperties; import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
...@@ -24,16 +25,11 @@ import org.springframework.data.redis.cache.RedisCacheConfiguration; ...@@ -24,16 +25,11 @@ import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
/** /**
* 缓存配置类 * 缓存配置类
...@@ -43,9 +39,17 @@ import java.util.Map; ...@@ -43,9 +39,17 @@ import java.util.Map;
@EnableCaching @EnableCaching
@Configuration @Configuration
@EnableConfigurationProperties(CacheProperties.class) @EnableConfigurationProperties(CacheProperties.class)
@ConditionalOnProperty("ibiz.enableCache") @ConditionalOnProperty("ibiz.enableRedisCache")
public class CacheConfig { public class RedisCacheConfig {
@Autowired
private RedisCacheWriter redisCacheWriter;
@Autowired
private RedisCacheConfiguration configuration;
@Autowired
LayeringCacheManager layeringCacheManager;
@Autowired
private CacheProperties cacheProperties;
@Bean @Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory connectionFactory) { public RedisCacheManager redisCacheManager(RedisConnectionFactory connectionFactory) {
return RedisCacheManager.create(connectionFactory); return RedisCacheManager.create(connectionFactory);
...@@ -57,12 +61,6 @@ public class CacheConfig { ...@@ -57,12 +61,6 @@ public class CacheConfig {
return redisCacheWriter; return redisCacheWriter;
} }
@Autowired
private RedisCacheWriter redisCacheWriter;
@Autowired
private RedisCacheConfiguration configuration;
/** /**
* 重写Redis序列化方式,使用Json方式: * 重写Redis序列化方式,使用Json方式:
* 当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializerStringRedisTemplate默认使用的是StringRedisSerializer * 当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializerStringRedisTemplate默认使用的是StringRedisSerializer
...@@ -92,41 +90,35 @@ public class CacheConfig { ...@@ -92,41 +90,35 @@ public class CacheConfig {
return redisTemplate; return redisTemplate;
} }
@Bean @Bean
@Primary @Primary
public CacheManager cacheManager(RedisTemplate<String, Object> redisTemplate) { public CacheManager cacheManager() {
LayeringCacheManager layeringCacheManager = new LayeringCacheManager(redisTemplate); setCaffeineCacheConfig(layeringCacheManager);//Caffeine缓存设置
setFirstCacheConfig(layeringCacheManager);//Caffeine缓存设置
layeringCacheManager.setAllowNullValues(true); //允许存null,防止缓存击穿
layeringCacheManager.setRedisCacheWriter(redisCacheWriter); layeringCacheManager.setRedisCacheWriter(redisCacheWriter);
layeringCacheManager.setRedisConfiguration(configuration); layeringCacheManager.setRedisConfiguration(configuration);
return layeringCacheManager; return layeringCacheManager;
} }
@Autowired private void setCaffeineCacheConfig(LayeringCacheManager layeringCacheManager) {
private CacheProperties cacheProperties;
private void setFirstCacheConfig(LayeringCacheManager layeringCacheManager) {
String specification = cacheProperties.getCaffeine().getSpec(); String specification = cacheProperties.getCaffeine().getSpec();
if (StringUtils.hasText(specification)) { if (StringUtils.hasText(specification)) {
layeringCacheManager.setCaffeineSpec(CaffeineSpec.parse(specification)); layeringCacheManager.setCaffeineSpec(CaffeineSpec.parse(specification));
} }
Map<String, FirstCacheSetting> firstCacheSettings = new HashMap<>();
layeringCacheManager.setFirstCacheSettings(firstCacheSettings);
} }
<#--/**--> /**
<#--* 监听redis指定频道--> * 监听redis指定频道
<#--* @param redisConnectionFactory--> * @param redisConnectionFactory
<#--* @param messageListener--> * @param messageListener
<#--* @return--> * @return
<#--*/--> */
<#--@Bean--> @Bean
<#--RedisMessageListenerContainer redisContainer(RedisConnectionFactory redisConnectionFactory, MessageListenerAdapter messageListener) {--> RedisMessageListenerContainer redisContainer(RedisConnectionFactory redisConnectionFactory, MessageListenerAdapter messageListener) {
<#--final RedisMessageListenerContainer container = new RedisMessageListenerContainer();--> final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
<#--container.setConnectionFactory(redisConnectionFactory);--> container.setConnectionFactory(redisConnectionFactory);
<#--container.addMessageListener(messageListener, RedisChannelTopic.REDIS_CACHE_DELETE_TOPIC.getChannelTopic());--> container.addMessageListener(messageListener, RedisChannelTopic.REDIS_CACHE_DELETE_TOPIC.getChannelTopic());
<#--container.addMessageListener(messageListener, RedisChannelTopic.REDIS_CACHE_CLEAR_TOPIC.getChannelTopic());--> container.addMessageListener(messageListener, RedisChannelTopic.REDIS_CACHE_CLEAR_TOPIC.getChannelTopic());
<#--return container;--> return container;
<#--}--> }
} }
\ No newline at end of file
<#ibiztemplate>
TARGET=PSSYSTEM
</#ibiztemplate>
package ${pub.getPKGCodeName()}.util.cache.cache;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
/**
* 自定义的redis缓存
*/
public class CusRedisCache extends RedisCache {
public CusRedisCache(String name, RedisCacheWriter redisCacheWriter, RedisCacheConfiguration configuration) {
super(name, redisCacheWriter, configuration);
}
}
<#ibiztemplate> <#ibiztemplate>
TARGET=PSSYSTEM TARGET=PSSYSTEM
</#ibiztemplate> </#ibiztemplate>
package ${pub.getPKGCodeName()}.util.cache.layering; package ${pub.getPKGCodeName()}.util.cache.cache;
import ${pub.getPKGCodeName()}.util.enums.RedisChannelTopic;
import ${pub.getPKGCodeName()}.util.cache.listener.RedisPublisher; import ${pub.getPKGCodeName()}.util.cache.listener.RedisPublisher;
import ${pub.getPKGCodeName()}.util.cache.redis.CustomizedRedisCache; import ${pub.getPKGCodeName()}.util.enums.RedisChannelTopic;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.cache.caffeine.CaffeineCache; import org.springframework.cache.caffeine.CaffeineCache;
...@@ -18,55 +17,41 @@ import org.springframework.data.redis.core.RedisOperations; ...@@ -18,55 +17,41 @@ import org.springframework.data.redis.core.RedisOperations;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
/** /**
* 缓存分层类 * 缓存分层类
* 1级缓存为caffeine * 1级缓存为caffeine
* 2级缓存为redis * 2级缓存为redis
*/ */
public class LayeringCache extends AbstractValueAdaptingCache { public class LayeringCache extends AbstractValueAdaptingCache {
Logger logger = LoggerFactory.getLogger(LayeringCache.class);
Logger logger = LoggerFactory.getLogger(LayeringCache.class);
/** /**
* 缓存的名称 * 缓存的名称
*/ */
private final String name; private final String name;
/**
* 是否使用一级缓存
*/
private boolean usedFirstCache = true;
/** /**
* redi缓存 * redis缓存
*/ */
private RedisCache redisCache; private RedisCache redisCache;
/** /**
* Caffeine缓存 * Caffeine缓存
*/ */
private final CaffeineCache caffeineCache; private final CaffeineCache caffeineCache;
RedisOperations<? extends Object, ? extends Object> redisOperations;
/** /**
* @param name 缓存名称 * redis消息发布
* @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, RedisOperations<? extends Object, ? extends Object> redisOperations;
public LayeringCache(String name ,RedisOperations redisOperations, com.github.benmanes.caffeine.cache.Cache<Object, Object> caffeineCache,
RedisCacheWriter redisCacheWriter, RedisCacheConfiguration configuration) { RedisCacheWriter redisCacheWriter, RedisCacheConfiguration configuration) {
super(allowNullValues); super(true);
this.name = name; this.name = name;
this.usedFirstCache = usedFirstCache; this.redisCache = new CusRedisCache(name, redisCacheWriter, configuration);
this.redisCache = new CustomizedRedisCache(name, redisCacheWriter, configuration); this.caffeineCache = new CaffeineCache(name, caffeineCache, true);
this.caffeineCache = new CaffeineCache(name, caffeineCache, allowNullValues);
this.redisOperations=redisOperations; this.redisOperations=redisOperations;
} }
public CaffeineCache getFirstCache() {
return this.caffeineCache;
}
@Override @Override
public String getName() { public String getName() {
return this.name; return this.name;
...@@ -79,13 +64,9 @@ public class LayeringCache extends AbstractValueAdaptingCache { ...@@ -79,13 +64,9 @@ public class LayeringCache extends AbstractValueAdaptingCache {
@Override @Override
public ValueWrapper get(Object key) { public ValueWrapper get(Object key) {
ValueWrapper wrapper = null;
if (usedFirstCache) {
// 查询一级缓存 // 查询一级缓存
wrapper = caffeineCache.get(key); ValueWrapper wrapper = caffeineCache.get(key);
logger.debug("查询一级缓存 key:{},value:{}", key,wrapper); logger.debug("查询一级缓存 key:{},value:{}", key,wrapper);
}
if (wrapper == null) { if (wrapper == null) {
// 查询二级缓存 // 查询二级缓存
wrapper = redisCache.get(key); wrapper = redisCache.get(key);
...@@ -97,12 +78,9 @@ public class LayeringCache extends AbstractValueAdaptingCache { ...@@ -97,12 +78,9 @@ public class LayeringCache extends AbstractValueAdaptingCache {
@Override @Override
public <T> T get(Object key, Class<T> type) { public <T> T get(Object key, Class<T> type) {
T value = null;
if (usedFirstCache) {
// 查询一级缓存 // 查询一级缓存
value = caffeineCache.get(key, type); T value = caffeineCache.get(key, type);
logger.debug("查询一级缓存 key:{}", key); logger.debug("查询一级缓存 key:{}", key);
}
if (value == null) { if (value == null) {
// 查询二级缓存 // 查询二级缓存
value = redisCache.get(key, type); value = redisCache.get(key, type);
...@@ -115,15 +93,12 @@ public class LayeringCache extends AbstractValueAdaptingCache { ...@@ -115,15 +93,12 @@ public class LayeringCache extends AbstractValueAdaptingCache {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public <T> T get(Object key, Callable<T> valueLoader) { public <T> T get(Object key, Callable<T> valueLoader) {
T value = null;
if (usedFirstCache) {
// 查询一级缓存,如果一级缓存没有值则调用getForSecondaryCache(k, valueLoader)查询二级缓存 // 查询一级缓存,如果一级缓存没有值则调用getForSecondaryCache(k, valueLoader)查询二级缓存
value = (T) caffeineCache.getNativeCache().get(key, k -> getForSecondaryCache(k, valueLoader)); T value = (T) caffeineCache.getNativeCache().get(key, k -> getSecondCache(k, valueLoader));
} else { if(value==null) {
// 直接查询二级缓存 // 直接查询二级缓存
value = (T) getForSecondaryCache(key, valueLoader); value = (T) getSecondCache(key, valueLoader);
} }
if (value instanceof NullValue) { if (value instanceof NullValue) {
return null; return null;
} }
...@@ -132,53 +107,42 @@ public class LayeringCache extends AbstractValueAdaptingCache { ...@@ -132,53 +107,42 @@ public class LayeringCache extends AbstractValueAdaptingCache {
@Override @Override
public void put(Object key, Object value) { public void put(Object key, Object value) {
if (usedFirstCache) {
caffeineCache.put(key, value); caffeineCache.put(key, value);
}
redisCache.put(key, value); redisCache.put(key, value);
} }
@Override @Override
public ValueWrapper putIfAbsent(Object key, Object value) { public ValueWrapper putIfAbsent(Object key, Object value) {
if (usedFirstCache) {
caffeineCache.putIfAbsent(key, value); caffeineCache.putIfAbsent(key, value);
}
return redisCache.putIfAbsent(key, value); return redisCache.putIfAbsent(key, value);
} }
@Override @Override
public void evict(Object key) { public void evict(Object key) {
redisCache.evict(key); //清除redis中的二级缓存 redisCache.evict(key); //清除redis中的二级缓存
if (usedFirstCache) {
caffeineCache.evict(key);//清除本机一级缓存 caffeineCache.evict(key);//清除本机一级缓存
Map<String, Object> message = new HashMap<>(); Map<String, Object> message = new HashMap<>();
message.put("cacheName", name); message.put("cacheName", name);
message.put("key", key); message.put("key", key);
RedisPublisher redisPublisher = new RedisPublisher(redisOperations, RedisChannelTopic.REDIS_CACHE_DELETE_TOPIC.getChannelTopic());// 创建redis发布者 RedisPublisher redisPublisher = new RedisPublisher(redisOperations, RedisChannelTopic.REDIS_CACHE_DELETE_TOPIC.getChannelTopic());// 创建redis发布者
redisPublisher.publisher(message);//发布消息,清除其它集群机器中的一级缓存 redisPublisher.publisher(message);//发布消息,清除其它集群机器中的一级缓存
}
logger.debug(String.format("清除二级缓存数据[%s]", key)); logger.debug(String.format("清除二级缓存数据[%s]", key));
} }
@Override @Override
public void clear() { public void clear() {
redisCache.clear(); //清除redis中的二级缓存 redisCache.clear(); //清除redis中的二级缓存
if (usedFirstCache) {
caffeineCache.clear();//清除本机一级缓存 caffeineCache.clear();//清除本机一级缓存
Map<String, Object> message = new HashMap<>(); Map<String, Object> message = new HashMap<>();
message.put("cacheName", name); message.put("cacheName", name);
RedisPublisher redisPublisher = new RedisPublisher(redisOperations, RedisChannelTopic.REDIS_CACHE_CLEAR_TOPIC.getChannelTopic());// 创建redis发布者 RedisPublisher redisPublisher = new RedisPublisher(redisOperations, RedisChannelTopic.REDIS_CACHE_CLEAR_TOPIC.getChannelTopic());// 创建redis发布者
redisPublisher.publisher(message);//发布消息,清除其它集群机器中的一级缓存 redisPublisher.publisher(message);//发布消息,清除其它集群机器中的一级缓存
} }
}
@Override @Override
protected Object lookup(Object key) { protected Object lookup(Object key) {
Object value = null; Object value = caffeineCache.get(key);
if (usedFirstCache) {
value = caffeineCache.get(key);
logger.debug("查询一级缓存 key:{}", key); logger.debug("查询一级缓存 key:{}", key);
}
if (value == null) { if (value == null) {
value = redisCache.get(key); value = redisCache.get(key);
logger.debug("查询二级缓存 key:{}", key); logger.debug("查询二级缓存 key:{}", key);
...@@ -192,9 +156,17 @@ public class LayeringCache extends AbstractValueAdaptingCache { ...@@ -192,9 +156,17 @@ public class LayeringCache extends AbstractValueAdaptingCache {
* @param valueLoader * @param valueLoader
* @return * @return
*/ */
private <T> Object getForSecondaryCache(Object key, Callable<T> valueLoader) { private <T> Object getSecondCache(Object key, Callable<T> valueLoader) {
T value = redisCache.get(key, valueLoader); T value = redisCache.get(key, valueLoader);
logger.debug("查询二级缓存 key:{}", key); logger.debug("查询二级缓存 key:{}", key);
return toStoreValue(value); return toStoreValue(value);
} }
/**
* 获取caffeine缓存
* @return
*/
public CaffeineCache getFirstCache() {
return this.caffeineCache;
}
} }
<#ibiztemplate>
TARGET=PSSYSTEM
</#ibiztemplate>
package ${pub.getPKGCodeName()}.util.cache.cacheManager;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.CaffeineSpec;
import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.stereotype.Component;
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;
/**
* Caffeine本地缓存
*/
@Data
@Component
@ConditionalOnProperty("ibiz.enableCaffeineCache")
public class CaffeineCacheManager implements CacheManager {
private static final int DEFAULT_EXPIRE_AFTER_WRITE = 1;
private static final int DEFAULT_INITIAL_CAPACITY = 5;
private static final int DEFAULT_MAXIMUM_SIZE = 1_000;
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>(16);
/**
* 缓存默认设置
*/
private Caffeine<Object, Object> cacheBuilder = Caffeine.newBuilder()
.expireAfterAccess(DEFAULT_EXPIRE_AFTER_WRITE, TimeUnit.HOURS)
.initialCapacity(DEFAULT_INITIAL_CAPACITY)
.maximumSize(DEFAULT_MAXIMUM_SIZE);
/**
* 获取缓存对象
* @param name
* @return
*/
@Override
public Cache getCache(String name) {
Cache cache = this.cacheMap.get(name);
if (cache == null) {
synchronized (this.cacheMap) {
cache = this.cacheMap.get(name);
if (cache == null) {
cache = createCache(name);
this.cacheMap.put(name, cache);
}
}
}
return cache;
}
/**
* 获取缓存名
* @return
*/
@Override
public Collection<String> getCacheNames() {
return Collections.unmodifiableSet(this.cacheMap.keySet());
}
/**
* 创建缓存
* @param name
* @return
*/
protected Cache createCache(String name) {
return new CaffeineCache(name, this.cacheBuilder.build(), true);
}
/**
* 缓存配置[缓存容量大小、时长等]
* @param caffeineSpec
*/
public void setCaffeineSpec(CaffeineSpec caffeineSpec) {
Caffeine<Object, Object> cacheBuilder = Caffeine.from(caffeineSpec);
if (!ObjectUtils.nullSafeEquals(this.cacheBuilder, cacheBuilder)) {
this.cacheBuilder = cacheBuilder;
refreshKnownCaches();
}
}
/**
* 使用该CacheManager的当前状态重新创建已知的缓存。
*/
private void refreshKnownCaches() {
for (Map.Entry<String, Cache> entry : this.cacheMap.entrySet()) {
entry.setValue(createCache(entry.getKey()));
}
}
}
<#ibiztemplate> <#ibiztemplate>
TARGET=PSSYSTEM TARGET=PSSYSTEM
</#ibiztemplate> </#ibiztemplate>
package ${pub.getPKGCodeName()}.util.cache.layering; package ${pub.getPKGCodeName()}.util.cache.cacheManager;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.CaffeineSpec; import com.github.benmanes.caffeine.cache.CaffeineSpec;
import ${pub.getPKGCodeName()}.util.cache.setting.FirstCacheSetting;
import ${pub.getPKGCodeName()}.util.cache.setting.SecondaryCacheSetting;
import lombok.Data; import lombok.Data;
import ${pub.getPKGCodeName()}.util.cache.cache.LayeringCache;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.Cache; import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils; import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
...@@ -22,7 +22,6 @@ import java.util.Map; ...@@ -22,7 +22,6 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.springframework.util.StringUtils;
/** /**
* 缓存分层类 * 缓存分层类
...@@ -30,40 +29,20 @@ import org.springframework.util.StringUtils; ...@@ -30,40 +29,20 @@ import org.springframework.util.StringUtils;
* 2级缓存为redis * 2级缓存为redis
*/ */
@Data @Data
@Component
@ConditionalOnProperty("ibiz.enableRedisCache")
public class LayeringCacheManager implements CacheManager { 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;
private static final int DEFAULT_EXPIRE_AFTER_WRITE = 1;
private static final int DEFAULT_INITIAL_CAPACITY = 5;
private static final int DEFAULT_MAXIMUM_SIZE = 1_000;
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>(16);
public RedisCacheWriter redisCacheWriter; public RedisCacheWriter redisCacheWriter;
public RedisCacheConfiguration redisConfiguration; public RedisCacheConfiguration redisConfiguration;
public RedisOperations redisOperations; public RedisOperations redisOperations;
/** /**
* 是否允许动态创建缓存,默认是true * 缓存默认设置
*/
private boolean dynamic = true;
/**
* 缓存值是否允许为NULL
*/
private boolean allowNullValues = false;
/**
* expireAfterWrite2 小时
* initialCapacity5
* maximumSize 1_000
*/ */
private Caffeine<Object, Object> cacheBuilder = Caffeine.newBuilder() private Caffeine<Object, Object> cacheBuilder = Caffeine.newBuilder()
.expireAfterAccess(DEFAULT_EXPIRE_AFTER_WRITE, TimeUnit.HOURS) .expireAfterAccess(DEFAULT_EXPIRE_AFTER_WRITE, TimeUnit.HOURS)
...@@ -82,7 +61,7 @@ public class LayeringCacheManager implements CacheManager { ...@@ -82,7 +61,7 @@ public class LayeringCacheManager implements CacheManager {
@Override @Override
public Cache getCache(String name) { public Cache getCache(String name) {
Cache cache = this.cacheMap.get(name); Cache cache = this.cacheMap.get(name);
if (cache == null && this.dynamic) { if (cache == null) {
synchronized (this.cacheMap) { synchronized (this.cacheMap) {
cache = this.cacheMap.get(name); cache = this.cacheMap.get(name);
if (cache == null) { if (cache == null) {
...@@ -100,21 +79,11 @@ public class LayeringCacheManager implements CacheManager { ...@@ -100,21 +79,11 @@ public class LayeringCacheManager implements CacheManager {
} }
protected Cache createCache(String name) { protected Cache createCache(String name) {
return new LayeringCache(name,isAllowNullValues(),this.redisOperations, getUsedFirstCache(name),createNativeCaffeineCache(name),redisCacheWriter,redisConfiguration); return new LayeringCache(name,this.redisOperations ,this.cacheBuilder.build(),redisCacheWriter,redisConfiguration);
} }
/** /**
* Create a native Caffeine Cache instance for the specified cache name. * 使用该CacheManager的当前状态重新创建已知的缓存
*
* @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() { private void refreshKnownCaches() {
for (Map.Entry<String, Cache> entry : this.cacheMap.entrySet()) { for (Map.Entry<String, Cache> entry : this.cacheMap.entrySet()) {
...@@ -122,48 +91,6 @@ public class LayeringCacheManager implements CacheManager { ...@@ -122,48 +91,6 @@ public class LayeringCacheManager implements CacheManager {
} }
} }
/**
* 设置是否允许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) { public void setCaffeineSpec(CaffeineSpec caffeineSpec) {
Caffeine<Object, Object> cacheBuilder = Caffeine.from(caffeineSpec); Caffeine<Object, Object> cacheBuilder = Caffeine.from(caffeineSpec);
if (!ObjectUtils.nullSafeEquals(this.cacheBuilder, cacheBuilder)) { if (!ObjectUtils.nullSafeEquals(this.cacheBuilder, cacheBuilder)) {
...@@ -171,14 +98,5 @@ public class LayeringCacheManager implements CacheManager { ...@@ -171,14 +98,5 @@ public class LayeringCacheManager implements CacheManager {
refreshKnownCaches(); 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;
}
} }
...@@ -3,26 +3,29 @@ TARGET=PSSYSTEM ...@@ -3,26 +3,29 @@ TARGET=PSSYSTEM
</#ibiztemplate> </#ibiztemplate>
package ${pub.getPKGCodeName()}.util.cache.listener; package ${pub.getPKGCodeName()}.util.cache.listener;
import ${pub.getPKGCodeName()}.util.cache.cache.LayeringCache;
import ${pub.getPKGCodeName()}.util.enums.RedisChannelTopic; import ${pub.getPKGCodeName()}.util.enums.RedisChannelTopic;
import ${pub.getPKGCodeName()}.util.cache.layering.LayeringCache;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.Cache; import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.connection.Message; import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.util.Map; import java.util.Map;
/** /**
* redis消息的订阅者 * redis消息的订阅者
*/ */
@Profile("prod")
@Component @Component
@ConditionalOnProperty("ibiz.enableRedisCache")
public class RedisMessageListener extends MessageListenerAdapter { public class RedisMessageListener extends MessageListenerAdapter {
private static final Logger logger = LoggerFactory.getLogger(RedisPublisher.class); private static final Logger logger = LoggerFactory.getLogger(RedisPublisher.class);
@Autowired @Autowired
...@@ -41,7 +44,7 @@ public class RedisMessageListener extends MessageListenerAdapter { ...@@ -41,7 +44,7 @@ public class RedisMessageListener extends MessageListenerAdapter {
map= (Map<String, Object>) result; map= (Map<String, Object>) result;
} }
if(StringUtils.isEmpty(map)|| (!map.containsKey("cacheName"))|| (!map.containsKey("key"))){ if(StringUtils.isEmpty(map)|| (!map.containsKey("cacheName"))|| (!map.containsKey("key"))){
logger.info("解析缓存数据失败,无法获取指定值!"); logger.debug("解析缓存数据失败,无法获取指定值!");
return ; return ;
} }
logger.debug("redis消息订阅者接收到频道【{}】发布的消息。消息内容:{}", channelTopic.getChannelTopicStr(), result.toString()); logger.debug("redis消息订阅者接收到频道【{}】发布的消息。消息内容:{}", channelTopic.getChannelTopicStr(), result.toString());
......
<#ibiztemplate>
TARGET=PSSYSTEM
</#ibiztemplate>
package ${pub.getPKGCodeName()}.util.cache.setting;
import com.github.benmanes.caffeine.cache.CaffeineSpec;
public class FirstCacheSetting {
/**
* 一级缓存配置,配置项请点击这里 {@link CaffeineSpec#configure(String, String)}
* @param cacheSpecification
*/
public FirstCacheSetting(String cacheSpecification) {
this.cacheSpecification = cacheSpecification;
}
private String cacheSpecification;
public String getCacheSpecification() {
return cacheSpecification;
}
}
<#ibiztemplate>
TARGET=PSSYSTEM
</#ibiztemplate>
package ${pub.getPKGCodeName()}.util.cache.setting;
public class SecondaryCacheSetting {
/**
* @param expirationSecondTime 设置redis缓存的有效时间,单位秒
* @param preloadSecondTime 设置redis缓存的自动刷新时间,单位秒
*/
public SecondaryCacheSetting(long expirationSecondTime, long preloadSecondTime) {
this.expirationSecondTime = expirationSecondTime;
this.preloadSecondTime = preloadSecondTime;
}
/**
* @param usedFirstCache 是否启用一级缓存,默认true
* @param expirationSecondTime 设置redis缓存的有效时间,单位秒
* @param preloadSecondTime 设置redis缓存的自动刷新时间,单位秒
*/
public SecondaryCacheSetting(boolean usedFirstCache, long expirationSecondTime, long preloadSecondTime) {
this.expirationSecondTime = expirationSecondTime;
this.preloadSecondTime = preloadSecondTime;
this.usedFirstCache = usedFirstCache;
}
/**
* @param expirationSecondTime 设置redis缓存的有效时间,单位秒
* @param preloadSecondTime 设置redis缓存的自动刷新时间,单位秒
* @param forceRefresh 是否使用强制刷新(走数据库),默认false
*/
public SecondaryCacheSetting(long expirationSecondTime, long preloadSecondTime, boolean forceRefresh) {
this.expirationSecondTime = expirationSecondTime;
this.preloadSecondTime = preloadSecondTime;
this.forceRefresh = forceRefresh;
}
/**
* @param expirationSecondTime 设置redis缓存的有效时间,单位秒
* @param preloadSecondTime 设置redis缓存的自动刷新时间,单位秒
* @param usedFirstCache 是否启用一级缓存,默认true
* @param forceRefresh 是否使用强制刷新(走数据库),默认false
*/
public SecondaryCacheSetting(long expirationSecondTime, long preloadSecondTime, boolean usedFirstCache, boolean forceRefresh) {
this.expirationSecondTime = expirationSecondTime;
this.preloadSecondTime = preloadSecondTime;
this.usedFirstCache = usedFirstCache;
this.forceRefresh = forceRefresh;
}
/**
* 缓存有效时间
*/
private long expirationSecondTime;
/**
* 缓存主动在失效前强制刷新缓存的时间
* 单位:秒
*/
private long preloadSecondTime = 0;
/**
* 是否使用一级缓存,默认是true
*/
private boolean usedFirstCache = true;
/**
* 是否使用强刷新(走数据库),默认是false
*/
private boolean forceRefresh = false;
public long getPreloadSecondTime() {
return preloadSecondTime;
}
public long getExpirationSecondTime() {
return expirationSecondTime;
}
public boolean getUsedFirstCache() {
return usedFirstCache;
}
public boolean getForceRefresh() {
return forceRefresh;
}
}
...@@ -124,12 +124,13 @@ ribbon: ...@@ -124,12 +124,13 @@ ribbon:
ReadTimeout: 60000 ReadTimeout: 60000
ConnectTimeout: 60000 ConnectTimeout: 60000
#系统是否开启权限验证、是否开启缓存 <#assign enableCache="false">
#系统是否开启权限验证、是否开启缓存 [本地缓存:enableCaffeineCache=true 或 两级缓存(caffeine+redis):enableRedisCache=true]
ibiz: ibiz:
enablePermissionValid: false enablePermissionValid: false
<#if sys.getPSSystemSetting()?? && sys.getPSSystemSetting().getDataAccCtrlArch()?? && sys.getPSSystemSetting().getDataAccCtrlArch()==1> <#if sys.getPSSystemSetting()?? && sys.getPSSystemSetting().getDataAccCtrlArch()?? && sys.getPSSystemSetting().getDataAccCtrlArch()==1>
enableCache: true <#assign enableCache="true">
<#else >
enableCache: false
</#if> </#if>
enableCaffeineCache: ${enableCache}
#enableRedisCache: ${enableCache}
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册