Commit 0f444738 authored by liaozan's avatar liaozan 🏀

Update cache operations

parent 52f6fe8d
package com.schbrain.framework.autoconfigure.cache;
import com.schbrain.framework.autoconfigure.cache.properties.CacheProperties;
import com.schbrain.framework.autoconfigure.cache.provider.CacheProvider;
import com.schbrain.framework.autoconfigure.cache.provider.CacheProviderDelegate;
import com.schbrain.framework.autoconfigure.cache.provider.CacheOperation;
import com.schbrain.framework.autoconfigure.cache.provider.PrefixedCacheOperation;
import com.schbrain.framework.autoconfigure.cache.provider.redis.RedisCacheConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
......@@ -23,11 +23,11 @@ import org.springframework.context.annotation.Import;
public class CacheAutoConfiguration {
@Bean
@ConditionalOnBean(CacheProvider.class)
public CacheProvider cacheProvider(CacheProvider cacheProvider, CacheProperties cacheProperties) {
CacheProvider provider = new CacheProviderDelegate(cacheProperties, cacheProvider);
CacheUtils.setCacheProvider(provider);
return provider;
@ConditionalOnBean(CacheOperation.class)
public PrefixedCacheOperation prefixedCacheOperation(CacheOperation cacheOperation, CacheProperties cacheProperties) {
PrefixedCacheOperation operation = new PrefixedCacheOperation(cacheProperties, cacheOperation);
CacheUtils.setCacheOperation(operation);
return operation;
}
}
package com.schbrain.framework.autoconfigure.cache;
import com.schbrain.framework.autoconfigure.cache.exception.CacheException;
import com.schbrain.framework.autoconfigure.cache.provider.CacheProvider;
import com.schbrain.framework.autoconfigure.cache.provider.PrefixedCacheOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
......@@ -12,45 +12,45 @@ import java.util.function.Supplier;
@Slf4j
public class CacheUtils {
private static CacheProvider cacheProvider;
private static PrefixedCacheOperation cacheOperation;
public static CacheProvider getCacheProvider() {
if (cacheProvider == null) {
throw new CacheException("CacheProvider is null, Please ensure the cache config is correct");
public static PrefixedCacheOperation getCacheOperation() {
if (cacheOperation == null) {
throw new CacheException("CacheOperation is null, Please ensure the cache config is correct");
}
return cacheProvider;
return cacheOperation;
}
public static void setCacheProvider(CacheProvider cacheProvider) {
CacheUtils.cacheProvider = cacheProvider;
public static void setCacheOperation(PrefixedCacheOperation cacheOperation) {
CacheUtils.cacheOperation = cacheOperation;
}
/**
* 缓存是否存在
*/
public static boolean hasKey(String cacheKey) {
return getCacheProvider().hasKey(cacheKey);
return getCacheOperation().hasKey(cacheKey);
}
/**
* 缓存是否过期
*/
public static boolean isExpired(String cacheKey) {
return getCacheProvider().isExpired(cacheKey);
return getCacheOperation().isExpired(cacheKey);
}
/**
* 设置过期时间
*/
public static void expire(String cacheKey, Duration expiration) {
getCacheProvider().expire(cacheKey, expiration);
getCacheOperation().expire(cacheKey, expiration);
}
/**
* 获取过期时间
*/
public static Duration getExpire(String cacheKey) {
return getCacheProvider().getExpire(cacheKey);
return getCacheOperation().getExpire(cacheKey);
}
/**
......@@ -64,35 +64,35 @@ public class CacheUtils {
* 模糊搜索 key, 默认采用 scan 实现
*/
public static Set<String> keys(String pattern, long limit) {
return getCacheProvider().keys(pattern, limit);
return getCacheOperation().keys(pattern, limit);
}
/**
* 获取缓存数据
*/
public static <T> T getValue(String cacheKey, Class<T> valueType) {
return getCacheProvider().get(cacheKey, valueType);
return getCacheOperation().getValue(cacheKey, valueType);
}
/**
* 设置缓存数据
*/
public static <T> void putValue(String cacheKey, T value, Duration expiration) {
getCacheProvider().set(cacheKey, value, expiration);
getCacheOperation().setValue(cacheKey, value, expiration);
}
/**
* 获取缓存数据列表
*/
public static <T> List<T> getList(String cacheKey, Class<T> valueType) {
return getCacheProvider().getList(cacheKey, valueType);
return getCacheOperation().getList(cacheKey, valueType);
}
/**
* 设置缓存数据列表
*/
public static <T> void putList(String cacheKey, List<T> value, Duration expiration) {
getCacheProvider().set(cacheKey, value, expiration);
getCacheOperation().setValue(cacheKey, value, expiration);
}
/**
......@@ -158,14 +158,14 @@ public class CacheUtils {
* 批量获取
*/
public static <T> Map<String, T> multiGet(Collection<String> cacheKeys, Class<T> valueType, boolean discardIfValueIsNull) {
return getCacheProvider().multiGet(cacheKeys, valueType, discardIfValueIsNull);
return getCacheOperation().multiGet(cacheKeys, valueType, discardIfValueIsNull);
}
/**
* 批量设置
*/
public static <T> void multiSet(Map<String, T> data, Duration expiration) {
getCacheProvider().multiSet(data, expiration);
getCacheOperation().multiSet(data, expiration);
}
/**
......@@ -179,7 +179,7 @@ public class CacheUtils {
* 删除缓存
*/
public static void del(List<String> cacheKeys) {
getCacheProvider().del(cacheKeys);
getCacheOperation().del(cacheKeys);
}
}
......@@ -9,8 +9,13 @@ import java.util.Set;
/**
* @author zhuyf
* @since 2020/9/24
**/
public interface CacheProvider {
*/
public interface CacheOperation {
/**
* 判断cacheKey是否存在
*/
boolean hasKey(String cacheKey);
/**
* 查询key是否过期
......@@ -27,11 +32,6 @@ public interface CacheProvider {
*/
Duration getExpire(String cacheKey);
/**
* 判断cacheKey是否存在
*/
boolean hasKey(String cacheKey);
/**
* 模糊搜索 key, 默认采用 scan 实现
*/
......@@ -45,12 +45,12 @@ public interface CacheProvider {
/**
* 缓存获取
*/
<T> T get(String cacheKey, Class<T> valueType);
<T> T getValue(String cacheKey, Class<T> valueType);
/**
* 缓存放入并设置时间
*/
<T> void set(String cacheKey, T value, Duration expiration);
<T> void setValue(String cacheKey, T value, Duration expiration);
/**
* 缓存放入并设置时间
......
......@@ -17,14 +17,13 @@ import java.util.Map.Entry;
* @author liaozan
* @since 2022/8/1
*/
public class CacheProviderDelegate implements CacheProvider {
public class PrefixedCacheOperation {
private final CacheOperation cacheOperation;
private final String prefixWithDelimiter;
private final CacheProvider cacheProvider;
public CacheProviderDelegate(CacheProperties properties, CacheProvider cacheProvider) {
this.cacheProvider = cacheProvider;
public PrefixedCacheOperation(CacheProperties properties, CacheOperation cacheOperation) {
this.cacheOperation = cacheOperation;
if (properties.isAppendPrefix()) {
String prefix = properties.getPrefix();
if (StringUtils.isBlank(prefix)) {
......@@ -36,54 +35,45 @@ public class CacheProviderDelegate implements CacheProvider {
}
}
@Override
public boolean hasKey(String cacheKey) {
return cacheOperation.hasKey(withKeyPrefix(cacheKey));
}
public boolean isExpired(String cacheKey) {
return getCacheProvider().isExpired(withKeyPrefix(cacheKey));
return cacheOperation.isExpired(withKeyPrefix(cacheKey));
}
@Override
public void expire(String cacheKey, Duration expiration) {
checkDuration(expiration);
getCacheProvider().expire(withKeyPrefix(cacheKey), expiration);
cacheOperation.expire(withKeyPrefix(cacheKey), expiration);
}
@Override
public Duration getExpire(String cacheKey) {
return getCacheProvider().getExpire(withKeyPrefix(cacheKey));
return cacheOperation.getExpire(withKeyPrefix(cacheKey));
}
@Override
public boolean hasKey(String cacheKey) {
return getCacheProvider().hasKey(withKeyPrefix(cacheKey));
}
@Override
public Set<String> keys(String pattern, long limit) {
Set<String> keys = getCacheProvider().keys(withKeyPrefix(pattern), limit);
Set<String> keys = cacheOperation.keys(withKeyPrefix(pattern), limit);
return StreamUtils.toSet(keys, this::removeKeyPrefix);
}
@Override
public void del(List<String> cacheKeys) {
if (CollectionUtils.isEmpty(cacheKeys)) {
return;
}
List<String> keysWithPrefix = StreamUtils.toList(cacheKeys, this::withKeyPrefix);
getCacheProvider().del(keysWithPrefix);
cacheOperation.del(keysWithPrefix);
}
@Override
public <T> T get(String cacheKey, Class<T> valueType) {
return getCacheProvider().get(withKeyPrefix(cacheKey), valueType);
public <T> T getValue(String cacheKey, Class<T> valueType) {
return cacheOperation.getValue(withKeyPrefix(cacheKey), valueType);
}
@Override
public <T> void set(String cacheKey, T value, Duration expiration) {
public <T> void setValue(String cacheKey, T value, Duration expiration) {
checkDuration(expiration);
getCacheProvider().set(withKeyPrefix(cacheKey), value, expiration);
cacheOperation.setValue(withKeyPrefix(cacheKey), value, expiration);
}
@Override
public <T> void multiSet(Map<String, T> data, Duration expiration) {
if (MapUtils.isEmpty(data)) {
return;
......@@ -93,16 +83,15 @@ public class CacheProviderDelegate implements CacheProvider {
for (Entry<String, T> entry : data.entrySet()) {
dataWithPrefixedKey.put(withKeyPrefix(entry.getKey()), entry.getValue());
}
getCacheProvider().multiSet(dataWithPrefixedKey, expiration);
cacheOperation.multiSet(dataWithPrefixedKey, expiration);
}
@Override
public <T> Map<String, T> multiGet(Collection<String> cacheKeys, Class<T> valueType, boolean discardIfValueIsNull) {
if (CollectionUtils.isEmpty(cacheKeys)) {
return Collections.emptyMap();
}
List<String> keysWithPrefix = StreamUtils.toList(cacheKeys, this::withKeyPrefix);
Map<String, T> dataWithPrefixedKey = getCacheProvider().multiGet(keysWithPrefix, valueType, discardIfValueIsNull);
Map<String, T> dataWithPrefixedKey = cacheOperation.multiGet(keysWithPrefix, valueType, discardIfValueIsNull);
if (MapUtils.isEmpty(dataWithPrefixedKey)) {
return Collections.emptyMap();
} else {
......@@ -115,13 +104,8 @@ public class CacheProviderDelegate implements CacheProvider {
}
}
@Override
public <T> List<T> getList(String cacheKey, Class<T> valueType) {
return getCacheProvider().getList(withKeyPrefix(cacheKey), valueType);
}
public CacheProvider getCacheProvider() {
return cacheProvider;
return cacheOperation.getList(withKeyPrefix(cacheKey), valueType);
}
protected String withKeyPrefix(String cacheKey) {
......
......@@ -21,10 +21,10 @@ public class RedisCacheConfiguration {
@Bean
@ConditionalOnBean(RedisConnectionFactory.class)
@ConditionalOnMissingBean(RedisCacheProvider.class)
public RedisCacheProvider redisCacheProvider(RedisConnectionFactory redisConnectionFactory, ObjectProvider<StringRedisTemplate> redisTemplate) {
StringRedisTemplate stringRedisTemplate = redisTemplate.getIfAvailable(() -> new StringRedisTemplate(redisConnectionFactory));
return new RedisCacheProvider(stringRedisTemplate);
@ConditionalOnMissingBean(RedisCacheOperation.class)
public RedisCacheOperation redisCacheProvider(RedisConnectionFactory factory, ObjectProvider<StringRedisTemplate> redisTemplate) {
StringRedisTemplate stringRedisTemplate = redisTemplate.getIfAvailable(() -> new StringRedisTemplate(factory));
return new RedisCacheOperation(stringRedisTemplate);
}
}
......@@ -4,8 +4,7 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.schbrain.common.util.JacksonUtils;
import com.schbrain.framework.autoconfigure.cache.exception.CacheException;
import com.schbrain.framework.autoconfigure.cache.provider.CacheProvider;
import lombok.extern.slf4j.Slf4j;
import com.schbrain.framework.autoconfigure.cache.provider.CacheOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
......@@ -22,37 +21,32 @@ import java.util.concurrent.TimeUnit;
/**
* @author zhuyf
* @since 2022/7/25
**/
@Slf4j
public class RedisCacheProvider implements CacheProvider {
*/
public class RedisCacheOperation implements CacheOperation {
private static final int DEFAULT_BATCH_SIZE = 100;
private final StringRedisTemplate redisTemplate;
public RedisCacheProvider(StringRedisTemplate redisTemplate) {
public RedisCacheOperation(StringRedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 查询key是否过期
*/
@Override
public boolean hasKey(String cacheKey) {
return Boolean.TRUE.equals(redisTemplate.hasKey(cacheKey));
}
@Override
public boolean isExpired(String cacheKey) {
return !hasKey(cacheKey);
}
/**
* 指定缓存失效时间
*/
@Override
public void expire(String key, Duration expiration) {
redisTemplate.expire(key, expiration.toMillis(), TimeUnit.MILLISECONDS);
}
/**
* 根据key 获取过期时间
*/
@Override
public Duration getExpire(String key) {
Long expiration = redisTemplate.getExpire(key, TimeUnit.MILLISECONDS);
......@@ -62,17 +56,6 @@ public class RedisCacheProvider implements CacheProvider {
return Duration.ofMillis(expiration);
}
/**
* 判断key是否存在
*/
@Override
public boolean hasKey(String cacheKey) {
return Boolean.TRUE.equals(redisTemplate.hasKey(cacheKey));
}
/**
* 模糊搜索 key
*/
@Override
public Set<String> keys(String pattern, long limit) {
Set<String> keys = new HashSet<>();
......@@ -88,9 +71,6 @@ public class RedisCacheProvider implements CacheProvider {
return keys;
}
/**
* 删除缓存
*/
@Override
public void del(List<String> cacheKeys) {
if (CollectionUtils.isEmpty(cacheKeys)) {
......@@ -99,61 +79,57 @@ public class RedisCacheProvider implements CacheProvider {
redisTemplate.delete(cacheKeys);
}
/**
* 缓存获取
*/
@Override
public <T> T get(String cacheKey, Class<T> type) {
public <T> T getValue(String cacheKey, Class<T> type) {
return JacksonUtils.getObjectFromJson(getValueFromRedis(cacheKey), type);
}
/**
* 普通缓存放入并设置时间
*/
@Override
public <T> void set(String cacheKey, T value, Duration expiration) {
public <T> void setValue(String cacheKey, T value, Duration expiration) {
setValueToRedis(cacheKey, value, expiration);
}
@Override
public <T> void multiSet(Map<String, T> data, Duration expiration) {
Iterables.partition(data.keySet(), DEFAULT_BATCH_SIZE).forEach(keys ->
redisTemplate.executePipelined((RedisCallback<Void>) connection -> {
Map<byte[], byte[]> byteMap = Maps.newHashMapWithExpectedSize(keys.size());
for (String key : keys) {
byteMap.put(key.getBytes(StandardCharsets.UTF_8), JacksonUtils.writeObjectAsBytes(data.get(key)));
}
connection.mSet(byteMap);
long expirationMillis = expiration.toMillis();
for (byte[] rawKey : byteMap.keySet()) {
connection.pExpire(rawKey, expirationMillis);
}
return null;
}));
Iterables.partition(data.keySet(), DEFAULT_BATCH_SIZE).forEach(keys -> redisTemplate.executePipelined(multiSet(data, expiration, keys)));
}
@Override
public <T> Map<String, T> multiGet(Collection<String> cacheKeys, Class<T> type, boolean discardIfValueIsNull) {
Map<String, T> result = Maps.newHashMapWithExpectedSize(cacheKeys.size());
Iterables.partition(cacheKeys, DEFAULT_BATCH_SIZE).forEach(subKeys -> {
List<String> valueList = Objects.requireNonNull(redisTemplate.opsForValue().multiGet(subKeys));
for (int i = 0; i < subKeys.size(); i++) {
Iterables.partition(cacheKeys, DEFAULT_BATCH_SIZE).forEach(subKeys -> multiGet(type, discardIfValueIsNull, subKeys, result));
return result;
}
@Override
public <T> List<T> getList(String cacheKey, Class<T> type) {
return JacksonUtils.getListFromJson(getValueFromRedis(cacheKey), type);
}
private <T> void multiGet(Class<T> type, boolean discardIfValueIsNull, List<String> keys, Map<String, T> result) {
List<String> valueList = Objects.requireNonNull(redisTemplate.opsForValue().multiGet(keys));
for (int i = 0; i < keys.size(); i++) {
T rawValue = JacksonUtils.getObjectFromJson(valueList.get(i), type);
if (discardIfValueIsNull && rawValue == null) {
continue;
}
result.put(subKeys.get(i), rawValue);
result.put(keys.get(i), rawValue);
}
});
return result;
}
/**
* list 缓存获取
*/
@Override
public <T> List<T> getList(String cacheKey, Class<T> type) {
return JacksonUtils.getListFromJson(getValueFromRedis(cacheKey), type);
private <T> RedisCallback<Void> multiSet(Map<String, T> data, Duration expiration, List<String> keys) {
return connection -> {
Map<byte[], byte[]> byteMap = Maps.newHashMapWithExpectedSize(keys.size());
for (String key : keys) {
byteMap.put(key.getBytes(StandardCharsets.UTF_8), JacksonUtils.writeObjectAsBytes(data.get(key)));
}
connection.mSet(byteMap);
long expirationMillis = expiration.toMillis();
for (byte[] rawKey : byteMap.keySet()) {
connection.pExpire(rawKey, expirationMillis);
}
return null;
};
}
private String getValueFromRedis(String cacheKey) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment