🎨 引入spring-java-format插件,代码格式管理
This commit is contained in:
@@ -12,29 +12,34 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
@ConfigurationProperties(prefix = "ballcat.redis")
|
||||
public class CacheProperties {
|
||||
|
||||
/**
|
||||
/**
|
||||
* 通用的key前缀
|
||||
*/
|
||||
private String keyPrefix = "";
|
||||
/**
|
||||
* redis锁 后缀
|
||||
*/
|
||||
private String lockKeySuffix = "locked";
|
||||
/**
|
||||
* 默认分隔符
|
||||
*/
|
||||
private String delimiter= ":";
|
||||
/**
|
||||
* 空值标识
|
||||
*/
|
||||
private String nullValue = "N_V";
|
||||
/**
|
||||
* 默认超时时间(s)
|
||||
*/
|
||||
private long expireTime = 86400L;
|
||||
/**
|
||||
* 锁的超时时间(ms)
|
||||
*/
|
||||
private long lockedTimeOut = 1000L;
|
||||
|
||||
/**
|
||||
* redis锁 后缀
|
||||
*/
|
||||
private String lockKeySuffix = "locked";
|
||||
|
||||
/**
|
||||
* 默认分隔符
|
||||
*/
|
||||
private String delimiter = ":";
|
||||
|
||||
/**
|
||||
* 空值标识
|
||||
*/
|
||||
private String nullValue = "N_V";
|
||||
|
||||
/**
|
||||
* 默认超时时间(s)
|
||||
*/
|
||||
private long expireTime = 86400L;
|
||||
|
||||
/**
|
||||
* 锁的超时时间(ms)
|
||||
*/
|
||||
private long lockedTimeOut = 1000L;
|
||||
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ package com.hccake.ballcat.common.redis.config;
|
||||
/**
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2020/3/20 16:56
|
||||
* 缓存配置持有者,方便静态获取配置信息
|
||||
* @date 2020/3/20 16:56 缓存配置持有者,方便静态获取配置信息
|
||||
*/
|
||||
public class CachePropertiesHolder {
|
||||
|
||||
private static CacheProperties cacheProperties;
|
||||
|
||||
public void setCacheProperties(CacheProperties cacheProperties) {
|
||||
@@ -18,24 +18,23 @@ public class CachePropertiesHolder {
|
||||
}
|
||||
|
||||
public static String lockKeySuffix() {
|
||||
return cacheProperties.getLockKeySuffix();
|
||||
}
|
||||
return cacheProperties.getLockKeySuffix();
|
||||
}
|
||||
|
||||
public static String delimiter() {
|
||||
return cacheProperties.getDelimiter();
|
||||
}
|
||||
public static String delimiter() {
|
||||
return cacheProperties.getDelimiter();
|
||||
}
|
||||
|
||||
public static String nullValue() {
|
||||
return cacheProperties.getNullValue();
|
||||
}
|
||||
public static String nullValue() {
|
||||
return cacheProperties.getNullValue();
|
||||
}
|
||||
|
||||
public static long expireTime() {
|
||||
return cacheProperties.getExpireTime();
|
||||
}
|
||||
|
||||
public static long lockedTimeOut() {
|
||||
return cacheProperties.getLockedTimeOut();
|
||||
}
|
||||
public static long expireTime() {
|
||||
return cacheProperties.getExpireTime();
|
||||
}
|
||||
|
||||
public static long lockedTimeOut() {
|
||||
return cacheProperties.getLockedTimeOut();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,25 +19,24 @@ import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
/**
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2019/9/2 14:13
|
||||
* 指定扫描包
|
||||
* @date 2019/9/2 14:13 指定扫描包
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@EnableConfigurationProperties(CacheProperties.class)
|
||||
public class RedisAutoConfiguration {
|
||||
|
||||
private final RedisConnectionFactory redisConnectionFactory;
|
||||
|
||||
|
||||
/**
|
||||
* 初始化配置类
|
||||
* @return GlobalCacheProperties
|
||||
*/
|
||||
@Bean
|
||||
public CachePropertiesHolder cachePropertiesHolder(CacheProperties cacheProperties){
|
||||
/**
|
||||
* 初始化配置类
|
||||
* @return GlobalCacheProperties
|
||||
*/
|
||||
@Bean
|
||||
public CachePropertiesHolder cachePropertiesHolder(CacheProperties cacheProperties) {
|
||||
CachePropertiesHolder cachePropertiesHolder = new CachePropertiesHolder();
|
||||
cachePropertiesHolder.setCacheProperties(cacheProperties);
|
||||
return cachePropertiesHolder;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认使用 Jackson 序列化
|
||||
@@ -45,9 +44,9 @@ public class RedisAutoConfiguration {
|
||||
* @return JacksonSerializer
|
||||
*/
|
||||
@Bean
|
||||
public CacheSerializer cacheSerializer(ObjectMapper objectMapper){
|
||||
return new JacksonSerializer(objectMapper);
|
||||
}
|
||||
public CacheSerializer cacheSerializer(ObjectMapper objectMapper) {
|
||||
return new JacksonSerializer(objectMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化CacheLock
|
||||
@@ -55,13 +54,12 @@ public class RedisAutoConfiguration {
|
||||
* @return CacheLock
|
||||
*/
|
||||
@Bean
|
||||
public CacheLock cacheLock(StringRedisTemplate stringRedisTemplate){
|
||||
public CacheLock cacheLock(StringRedisTemplate stringRedisTemplate) {
|
||||
CacheLock cacheLock = new CacheLock();
|
||||
cacheLock.setStringRedisTemplate(stringRedisTemplate);
|
||||
return cacheLock;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
@DependsOn("cachePropertiesHolder")
|
||||
@ConditionalOnProperty(name = "ballcat.redis.key-prefix")
|
||||
@@ -84,6 +82,4 @@ public class RedisAutoConfiguration {
|
||||
return template;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -13,57 +13,53 @@ import java.util.concurrent.TimeUnit;
|
||||
/**
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2020/3/27 21:15
|
||||
* 缓存锁的操作类
|
||||
* @date 2020/3/27 21:15 缓存锁的操作类
|
||||
*/
|
||||
public class CacheLock {
|
||||
private static final Logger log = LoggerFactory.getLogger(CacheLock.class);
|
||||
private static StringRedisTemplate redisTemplate;
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CacheLock.class);
|
||||
|
||||
private static StringRedisTemplate redisTemplate;
|
||||
|
||||
public void setStringRedisTemplate(StringRedisTemplate redisTemplate) {
|
||||
CacheLock.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上锁
|
||||
* @param requestId 请求id
|
||||
* @return Boolean 是否成功获得锁
|
||||
*/
|
||||
public static Boolean lock(String lockKey, String requestId) {
|
||||
log.info("lock: {key:{}, clientId:{}}", lockKey, requestId);
|
||||
return redisTemplate.opsForValue().setIfAbsent(lockKey, requestId, CachePropertiesHolder.lockedTimeOut(),
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上锁
|
||||
* @param requestId 请求id
|
||||
* @return Boolean 是否成功获得锁
|
||||
*/
|
||||
public static Boolean lock(String lockKey, String requestId) {
|
||||
log.info("lock: {key:{}, clientId:{}}", lockKey, requestId);
|
||||
return redisTemplate.opsForValue()
|
||||
.setIfAbsent(lockKey, requestId, CachePropertiesHolder.lockedTimeOut(), TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* 释放锁lua脚本
|
||||
* KEYS【1】:key值是为要加的锁定义的字符串常量
|
||||
* ARGV【1】:value值是 request id, 用来防止解除了不该解除的锁. 可用 UUID
|
||||
*/
|
||||
private static final String RELEASE_LOCK_LUA_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
|
||||
/**
|
||||
* 释放锁成功返回值
|
||||
*/
|
||||
private static final Long RELEASE_LOCK_SUCCESS_RESULT = 1L;
|
||||
|
||||
/**
|
||||
* 释放锁
|
||||
*
|
||||
* @param key 锁ID
|
||||
* @param requestId 请求ID
|
||||
* @return 是否成功
|
||||
*/
|
||||
public static boolean releaseLock(String key, String requestId) {
|
||||
log.info("release lock: {key:{}, clientId:{}}", key, requestId);
|
||||
//指定ReturnType为Long.class
|
||||
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(RELEASE_LOCK_LUA_SCRIPT, Long.class);
|
||||
Long result = redisTemplate.execute(redisScript, Collections.singletonList(key), requestId);
|
||||
return Objects.equals(result, RELEASE_LOCK_SUCCESS_RESULT);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* 释放锁lua脚本 KEYS【1】:key值是为要加的锁定义的字符串常量 ARGV【1】:value值是 request id, 用来防止解除了不该解除的锁. 可用
|
||||
* UUID
|
||||
*/
|
||||
private static final String RELEASE_LOCK_LUA_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
|
||||
|
||||
/**
|
||||
* 释放锁成功返回值
|
||||
*/
|
||||
private static final Long RELEASE_LOCK_SUCCESS_RESULT = 1L;
|
||||
|
||||
/**
|
||||
* 释放锁
|
||||
* @param key 锁ID
|
||||
* @param requestId 请求ID
|
||||
* @return 是否成功
|
||||
*/
|
||||
public static boolean releaseLock(String key, String requestId) {
|
||||
log.info("release lock: {key:{}, clientId:{}}", key, requestId);
|
||||
// 指定ReturnType为Long.class
|
||||
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(RELEASE_LOCK_LUA_SCRIPT, Long.class);
|
||||
Long result = redisTemplate.execute(redisScript, Collections.singletonList(key), requestId);
|
||||
return Objects.equals(result, RELEASE_LOCK_SUCCESS_RESULT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,170 +35,168 @@ import java.util.function.Supplier;
|
||||
*/
|
||||
@Aspect
|
||||
public class CacheStringAspect {
|
||||
Logger log = LoggerFactory.getLogger(CacheStringAspect.class);
|
||||
private final CacheSerializer cacheSerializer;
|
||||
private final StringRedisTemplate redisTemplate;
|
||||
|
||||
public CacheStringAspect(StringRedisTemplate redisTemplate, CacheSerializer cacheSerializer){
|
||||
this.redisTemplate = redisTemplate;
|
||||
this.cacheSerializer = cacheSerializer;
|
||||
}
|
||||
Logger log = LoggerFactory.getLogger(CacheStringAspect.class);
|
||||
|
||||
@Pointcut("execution(@(@com.hccake.ballcat.common.redis.core.annotation.MetaCacheAnnotation *) * *(..))")
|
||||
public void pointCut() {}
|
||||
private final CacheSerializer cacheSerializer;
|
||||
|
||||
@Around("pointCut()")
|
||||
public Object around(ProceedingJoinPoint point) throws Throwable {
|
||||
private final StringRedisTemplate redisTemplate;
|
||||
|
||||
//获取目标方法
|
||||
MethodSignature signature = (MethodSignature) point.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
public CacheStringAspect(StringRedisTemplate redisTemplate, CacheSerializer cacheSerializer) {
|
||||
this.redisTemplate = redisTemplate;
|
||||
this.cacheSerializer = cacheSerializer;
|
||||
}
|
||||
|
||||
log.trace("=======The string cache aop is executed! method : {}", method.getName());
|
||||
@Pointcut("execution(@(@com.hccake.ballcat.common.redis.core.annotation.MetaCacheAnnotation *) * *(..))")
|
||||
public void pointCut() {
|
||||
}
|
||||
|
||||
//根据方法的参数 以及当前类对象获得 keyGenerator
|
||||
Object target = point.getTarget();
|
||||
Object[] arguments = point.getArgs();
|
||||
KeyGenerator keyGenerator = new KeyGenerator(target, method, arguments);
|
||||
@Around("pointCut()")
|
||||
public Object around(ProceedingJoinPoint point) throws Throwable {
|
||||
|
||||
ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
|
||||
// 获取目标方法
|
||||
MethodSignature signature = (MethodSignature) point.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
|
||||
//获取注解对象
|
||||
Cached cachedAnnotation = AnnotationUtils.getAnnotation(method, Cached.class);
|
||||
if(cachedAnnotation != null){
|
||||
//缓存key
|
||||
String key = keyGenerator.getKey(cachedAnnotation.key(), cachedAnnotation.keyJoint());
|
||||
//redis 分布式锁的 key
|
||||
String lockKey = key + CachePropertiesHolder.lockKeySuffix();
|
||||
Supplier<String> cacheQuery = () -> valueOperations.get(key);
|
||||
// 失效时间控制
|
||||
Consumer<Object> cachePut = prodCachePutFunction(valueOperations, key, cachedAnnotation.ttl());
|
||||
return cached(new CachedOps(point, lockKey, cacheQuery, cachePut, method.getGenericReturnType()));
|
||||
log.trace("=======The string cache aop is executed! method : {}", method.getName());
|
||||
|
||||
}
|
||||
// 根据方法的参数 以及当前类对象获得 keyGenerator
|
||||
Object target = point.getTarget();
|
||||
Object[] arguments = point.getArgs();
|
||||
KeyGenerator keyGenerator = new KeyGenerator(target, method, arguments);
|
||||
|
||||
CachePut cachePutAnnotation = AnnotationUtils.getAnnotation(method, CachePut.class);
|
||||
if(cachePutAnnotation != null){
|
||||
//缓存key
|
||||
String key = keyGenerator.getKey(cachePutAnnotation.key(), cachePutAnnotation.keyJoint());
|
||||
// 失效时间控制
|
||||
Consumer<Object> cachePut = prodCachePutFunction(valueOperations, key, cachePutAnnotation.ttl());
|
||||
return cachePut(new CachePutOps(point, cachePut));
|
||||
}
|
||||
ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
|
||||
|
||||
// 获取注解对象
|
||||
Cached cachedAnnotation = AnnotationUtils.getAnnotation(method, Cached.class);
|
||||
if (cachedAnnotation != null) {
|
||||
// 缓存key
|
||||
String key = keyGenerator.getKey(cachedAnnotation.key(), cachedAnnotation.keyJoint());
|
||||
// redis 分布式锁的 key
|
||||
String lockKey = key + CachePropertiesHolder.lockKeySuffix();
|
||||
Supplier<String> cacheQuery = () -> valueOperations.get(key);
|
||||
// 失效时间控制
|
||||
Consumer<Object> cachePut = prodCachePutFunction(valueOperations, key, cachedAnnotation.ttl());
|
||||
return cached(new CachedOps(point, lockKey, cacheQuery, cachePut, method.getGenericReturnType()));
|
||||
|
||||
CacheDel cacheDelAnnotation = AnnotationUtils.getAnnotation(method, CacheDel.class);
|
||||
if(cacheDelAnnotation != null){
|
||||
//缓存key
|
||||
String key = keyGenerator.getKey(cacheDelAnnotation.key(), cacheDelAnnotation.keyJoint());
|
||||
VoidMethod cacheDel = () -> redisTemplate.delete(key);
|
||||
return cacheDel(new CacheDelOps(point, cacheDel));
|
||||
}
|
||||
}
|
||||
|
||||
return point.proceed();
|
||||
}
|
||||
CachePut cachePutAnnotation = AnnotationUtils.getAnnotation(method, CachePut.class);
|
||||
if (cachePutAnnotation != null) {
|
||||
// 缓存key
|
||||
String key = keyGenerator.getKey(cachePutAnnotation.key(), cachePutAnnotation.keyJoint());
|
||||
// 失效时间控制
|
||||
Consumer<Object> cachePut = prodCachePutFunction(valueOperations, key, cachePutAnnotation.ttl());
|
||||
return cachePut(new CachePutOps(point, cachePut));
|
||||
}
|
||||
|
||||
private Consumer<Object> prodCachePutFunction(ValueOperations<String, String> valueOperations, String key, long ttl) {
|
||||
Consumer<Object> cachePut;
|
||||
if (ttl < 0) {
|
||||
cachePut = value -> valueOperations.set(key, (String) value);
|
||||
} else if (ttl == 0) {
|
||||
cachePut = value -> valueOperations.set(key, (String) value, CachePropertiesHolder.expireTime(), TimeUnit.SECONDS);
|
||||
} else {
|
||||
cachePut = value -> valueOperations.set(key, (String) value, ttl, TimeUnit.SECONDS);
|
||||
}
|
||||
return cachePut;
|
||||
}
|
||||
CacheDel cacheDelAnnotation = AnnotationUtils.getAnnotation(method, CacheDel.class);
|
||||
if (cacheDelAnnotation != null) {
|
||||
// 缓存key
|
||||
String key = keyGenerator.getKey(cacheDelAnnotation.key(), cacheDelAnnotation.keyJoint());
|
||||
VoidMethod cacheDel = () -> redisTemplate.delete(key);
|
||||
return cacheDel(new CacheDelOps(point, cacheDel));
|
||||
}
|
||||
|
||||
return point.proceed();
|
||||
}
|
||||
|
||||
private Consumer<Object> prodCachePutFunction(ValueOperations<String, String> valueOperations, String key,
|
||||
long ttl) {
|
||||
Consumer<Object> cachePut;
|
||||
if (ttl < 0) {
|
||||
cachePut = value -> valueOperations.set(key, (String) value);
|
||||
}
|
||||
else if (ttl == 0) {
|
||||
cachePut = value -> valueOperations.set(key, (String) value, CachePropertiesHolder.expireTime(),
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
else {
|
||||
cachePut = value -> valueOperations.set(key, (String) value, ttl, TimeUnit.SECONDS);
|
||||
}
|
||||
return cachePut;
|
||||
}
|
||||
|
||||
/**
|
||||
* cached 类型的模板方法 1. 先查缓存 若有数据则直接返回 2. 尝试获取锁 若成功执行目标方法(一般是去查数据库) 3. 将数据库获取到数据同步至缓存
|
||||
* @param ops
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public Object cached(CachedOps ops) throws Throwable {
|
||||
|
||||
/**
|
||||
* cached 类型的模板方法
|
||||
* 1. 先查缓存 若有数据则直接返回
|
||||
* 2. 尝试获取锁 若成功执行目标方法(一般是去查数据库)
|
||||
* 3. 将数据库获取到数据同步至缓存
|
||||
*
|
||||
* @param ops
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public Object cached(CachedOps ops) throws Throwable {
|
||||
// 缓存查询方法
|
||||
Supplier<String> cacheQuery = ops.cacheQuery();
|
||||
// 返回数据类型
|
||||
Type dataClazz = ops.returnType();
|
||||
|
||||
//缓存查询方法
|
||||
Supplier<String> cacheQuery = ops.cacheQuery();
|
||||
//返回数据类型
|
||||
Type dataClazz = ops.returnType();
|
||||
// 1.==================尝试从缓存获取数据==========================
|
||||
String cacheData = cacheQuery.get();
|
||||
// 如果是空值 则return null | 不是空值且不是null 则直接返回
|
||||
if (ops.nullValue(cacheData)) {
|
||||
return null;
|
||||
}
|
||||
else if (cacheData != null) {
|
||||
return cacheSerializer.deserialize(cacheData, dataClazz);
|
||||
}
|
||||
|
||||
//1.==================尝试从缓存获取数据==========================
|
||||
String cacheData = cacheQuery.get();
|
||||
//如果是空值 则return null | 不是空值且不是null 则直接返回
|
||||
if (ops.nullValue(cacheData)) {
|
||||
return null;
|
||||
} else if (cacheData != null) {
|
||||
return cacheSerializer.deserialize(cacheData, dataClazz);
|
||||
}
|
||||
// 2.==========如果缓存为空 则需查询数据库并更新===============
|
||||
Object dbData = null;
|
||||
// 尝试获取锁,只允许一个线程更新缓存
|
||||
String reqId = UUID.randomUUID().toString();
|
||||
if (CacheLock.lock(ops.lockKey(), reqId)) {
|
||||
// 有可能其他线程已经更新缓存,这里再次判断缓存是否为空
|
||||
cacheData = cacheQuery.get();
|
||||
if (cacheData == null) {
|
||||
// 从数据库查询数据
|
||||
dbData = ops.joinPoint().proceed();
|
||||
// 如果数据库中没数据,填充一个String,防止缓存击穿
|
||||
cacheData = dbData == null ? CachePropertiesHolder.nullValue() : cacheSerializer.serialize(dbData);
|
||||
// 设置缓存
|
||||
ops.cachePut().accept(cacheData);
|
||||
}
|
||||
// 解锁
|
||||
CacheLock.releaseLock(ops.lockKey(), reqId);
|
||||
// 返回数据
|
||||
return dbData;
|
||||
}
|
||||
else {
|
||||
cacheData = cacheQuery.get();
|
||||
}
|
||||
|
||||
//2.==========如果缓存为空 则需查询数据库并更新===============
|
||||
Object dbData = null;
|
||||
//尝试获取锁,只允许一个线程更新缓存
|
||||
String reqId = UUID.randomUUID().toString();
|
||||
if (CacheLock.lock(ops.lockKey(), reqId)) {
|
||||
//有可能其他线程已经更新缓存,这里再次判断缓存是否为空
|
||||
cacheData = cacheQuery.get();
|
||||
if (cacheData == null) {
|
||||
//从数据库查询数据
|
||||
dbData = ops.joinPoint().proceed();
|
||||
//如果数据库中没数据,填充一个String,防止缓存击穿
|
||||
cacheData = dbData == null ? CachePropertiesHolder.nullValue() : cacheSerializer.serialize(dbData);
|
||||
//设置缓存
|
||||
ops.cachePut().accept(cacheData);
|
||||
}
|
||||
//解锁
|
||||
CacheLock.releaseLock(ops.lockKey(), reqId);
|
||||
//返回数据
|
||||
return dbData;
|
||||
} else {
|
||||
cacheData = cacheQuery.get();
|
||||
}
|
||||
// 自旋时间内未获取到锁,或者数据库中数据为空,返回null
|
||||
if (cacheData == null || ops.nullValue(cacheData)) {
|
||||
return null;
|
||||
}
|
||||
return cacheSerializer.deserialize(cacheData, dataClazz);
|
||||
}
|
||||
|
||||
//自旋时间内未获取到锁,或者数据库中数据为空,返回null
|
||||
if (cacheData == null || ops.nullValue(cacheData)) {
|
||||
return null;
|
||||
}
|
||||
return cacheSerializer.deserialize(cacheData, dataClazz);
|
||||
}
|
||||
/**
|
||||
* 缓存操作模板方法
|
||||
*/
|
||||
public Object cachePut(CachePutOps ops) throws Throwable {
|
||||
|
||||
// 先执行目标方法 并拿到返回值
|
||||
Object data = ops.joinPoint().proceed();
|
||||
|
||||
/**
|
||||
* 缓存操作模板方法
|
||||
*/
|
||||
public Object cachePut(CachePutOps ops) throws Throwable {
|
||||
// 将返回值放置入缓存中
|
||||
String cacheData = data == null ? CachePropertiesHolder.nullValue() : cacheSerializer.serialize(data);
|
||||
ops.cachePut().accept(cacheData);
|
||||
|
||||
//先执行目标方法 并拿到返回值
|
||||
Object data = ops.joinPoint().proceed();
|
||||
return data;
|
||||
}
|
||||
|
||||
//将返回值放置入缓存中
|
||||
String cacheData = data == null ? CachePropertiesHolder.nullValue() : cacheSerializer.serialize(data);
|
||||
ops.cachePut().accept(cacheData);
|
||||
/**
|
||||
* 缓存删除的模板方法 在目标方法执行后 执行删除
|
||||
*/
|
||||
public Object cacheDel(CacheDelOps ops) throws Throwable {
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 缓存删除的模板方法
|
||||
* 在目标方法执行后 执行删除
|
||||
*/
|
||||
public Object cacheDel(CacheDelOps ops) throws Throwable {
|
||||
|
||||
//先执行目标方法 并拿到返回值
|
||||
Object data = ops.joinPoint().proceed();
|
||||
//将删除缓存
|
||||
ops.cacheDel().run();
|
||||
|
||||
return data;
|
||||
}
|
||||
// 先执行目标方法 并拿到返回值
|
||||
Object data = ops.joinPoint().proceed();
|
||||
// 将删除缓存
|
||||
ops.cacheDel().run();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,108 +14,96 @@ import java.util.List;
|
||||
/**
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2019/9/3 9:58
|
||||
* 缓存key的生成工具类,主要用于解析spel, 进行拼接key的生成
|
||||
* @date 2019/9/3 9:58 缓存key的生成工具类,主要用于解析spel, 进行拼接key的生成
|
||||
*/
|
||||
public class KeyGenerator {
|
||||
|
||||
/**
|
||||
* SpEL 上下文
|
||||
*/
|
||||
StandardEvaluationContext spElContext;
|
||||
/**
|
||||
* SpEL 上下文
|
||||
*/
|
||||
StandardEvaluationContext spElContext;
|
||||
|
||||
public KeyGenerator(Object target, Method method, Object[] arguments) {
|
||||
this.spElContext = SpELUtil.getSpElContext(target, method, arguments);
|
||||
}
|
||||
public KeyGenerator(Object target, Method method, Object[] arguments) {
|
||||
this.spElContext = SpELUtil.getSpElContext(target, method, arguments);
|
||||
}
|
||||
|
||||
public String getKey(String key, String spELExpressions) {
|
||||
// 根据keyJoint 判断是否需要拼接
|
||||
if (spELExpressions == null || spELExpressions.length() == 0) {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getKey(String key, String spELExpressions) {
|
||||
//根据keyJoint 判断是否需要拼接
|
||||
if (spELExpressions == null || spELExpressions.length() == 0) {
|
||||
return key;
|
||||
}
|
||||
// 获取所有需要拼接的元素, 组装进集合中
|
||||
String joint = SpELUtil.parseValueToString(spElContext, spELExpressions);
|
||||
Assert.notNull(joint, "Key joint cannot be null!");
|
||||
|
||||
//获取所有需要拼接的元素, 组装进集合中
|
||||
String joint = SpELUtil.parseValueToString(spElContext, spELExpressions);
|
||||
Assert.notNull(joint, "Key joint cannot be null!");
|
||||
if (StringUtils.isEmpty(key)) {
|
||||
return joint;
|
||||
}
|
||||
// 拼接后返回
|
||||
return jointKey(key, joint);
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(key)) {
|
||||
return joint;
|
||||
}
|
||||
//拼接后返回
|
||||
return jointKey(key, joint);
|
||||
}
|
||||
public List<String> getKeys(String key, String keyJoint, Collection<String> multiByItem) {
|
||||
String keyPrefix = getKey(key, keyJoint);
|
||||
|
||||
List<String> list = new ArrayList<>();
|
||||
for (String item : multiByItem) {
|
||||
list.add(jointKey(keyPrefix, item));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<String> getKeys(String key, String keyJoint, Collection<String> multiByItem) {
|
||||
String keyPrefix = getKey(key, keyJoint);
|
||||
/**
|
||||
* @param key
|
||||
* @param spELExpressions
|
||||
* @return
|
||||
*/
|
||||
public String getKeys(String key, String[] spELExpressions) {
|
||||
// 根据keyJoint 判断是否需要拼接
|
||||
if (spELExpressions == null || spELExpressions.length == 0) {
|
||||
return key;
|
||||
}
|
||||
|
||||
List<String> list = new ArrayList<>();
|
||||
for (String item : multiByItem) {
|
||||
list.add(jointKey(keyPrefix, item));
|
||||
}
|
||||
// 获取所有需要拼接的元素, 组装进集合中
|
||||
List<String> list = new ArrayList<>(spELExpressions.length + 1);
|
||||
list.add(key);
|
||||
for (String joint : spELExpressions) {
|
||||
String s = parseSpEL(joint);
|
||||
Assert.notNull(s, "Key joint cannot be null!");
|
||||
list.add(s);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
// 拼接后返回
|
||||
return jointKey(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析SPEL
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public String parseSpEL(String field) {
|
||||
return SpELUtil.parseValueToString(spElContext, field);
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接key, 默认使用 :作为分隔符
|
||||
* @param list
|
||||
* @return
|
||||
*/
|
||||
public String jointKey(List<String> list) {
|
||||
return String.join(CachePropertiesHolder.delimiter(), list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* @param spELExpressions
|
||||
* @return
|
||||
*/
|
||||
public String getKeys(String key, String[] spELExpressions) {
|
||||
//根据keyJoint 判断是否需要拼接
|
||||
if (spELExpressions == null || spELExpressions.length == 0) {
|
||||
return key;
|
||||
}
|
||||
|
||||
//获取所有需要拼接的元素, 组装进集合中
|
||||
List<String> list = new ArrayList<>(spELExpressions.length + 1);
|
||||
list.add(key);
|
||||
for (String joint : spELExpressions) {
|
||||
String s = parseSpEL(joint);
|
||||
Assert.notNull(s, "Key joint cannot be null!");
|
||||
list.add(s);
|
||||
}
|
||||
|
||||
//拼接后返回
|
||||
return jointKey(list);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 解析SPEL
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public String parseSpEL(String field) {
|
||||
return SpELUtil.parseValueToString(spElContext, field);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 拼接key, 默认使用 :作为分隔符
|
||||
* @param list
|
||||
* @return
|
||||
*/
|
||||
public String jointKey(List<String> list) {
|
||||
return String.join(CachePropertiesHolder.delimiter(), list);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 拼接key, 默认使用 :作为分隔符
|
||||
* @param items
|
||||
* @return
|
||||
*/
|
||||
public String jointKey(String... items) {
|
||||
return jointKey(Arrays.asList(items));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 拼接key, 默认使用 :作为分隔符
|
||||
* @param items
|
||||
* @return
|
||||
*/
|
||||
public String jointKey(String... items) {
|
||||
return jointKey(Arrays.asList(items));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,64 +16,54 @@ import java.lang.reflect.Method;
|
||||
*/
|
||||
public class SpELUtil {
|
||||
|
||||
/**
|
||||
* SpEL 解析器
|
||||
*/
|
||||
public static final ExpressionParser PARSER = new SpelExpressionParser();
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* 方法参数获取
|
||||
*/
|
||||
public static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 支持 #p0 参数索引的表达式解析
|
||||
* @param rootObject 根对象,method 所在的对象
|
||||
* @param spEL 表达式
|
||||
* @param method 目标方法
|
||||
* @param args 方法入参
|
||||
* @return 解析后的字符串
|
||||
*/
|
||||
public static String parseValueToString(Object rootObject, Method method, Object[] args, String spEL) {
|
||||
|
||||
StandardEvaluationContext context = getSpElContext(rootObject, method, args);
|
||||
return parseValueToString(context, spEL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 支持 #p0 参数索引的表达式解析
|
||||
* @param rootObject 根对象,method 所在的对象
|
||||
* @param method ,目标方法
|
||||
* @param args 方法入参
|
||||
* @return 解析后的字符串
|
||||
*/
|
||||
public static StandardEvaluationContext getSpElContext(Object rootObject, Method method, Object[] args) {
|
||||
|
||||
String[] paraNameArr = PARAMETER_NAME_DISCOVERER.getParameterNames(method);
|
||||
// SPEL 上下文
|
||||
StandardEvaluationContext context = new MethodBasedEvaluationContext(rootObject, method, args, PARAMETER_NAME_DISCOVERER);
|
||||
// 把方法参数放入 SPEL 上下文中
|
||||
for (int i = 0; i < paraNameArr.length; i++) {
|
||||
context.setVariable(paraNameArr[i], args[i]);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
public static String parseValueToString(StandardEvaluationContext context, String spEL) {
|
||||
return PARSER.parseExpression(spEL).getValue(context, String.class);
|
||||
}
|
||||
/**
|
||||
* SpEL 解析器
|
||||
*/
|
||||
public static final ExpressionParser PARSER = new SpelExpressionParser();
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* 方法参数获取
|
||||
*/
|
||||
public static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
/**
|
||||
* 支持 #p0 参数索引的表达式解析
|
||||
* @param rootObject 根对象,method 所在的对象
|
||||
* @param spEL 表达式
|
||||
* @param method 目标方法
|
||||
* @param args 方法入参
|
||||
* @return 解析后的字符串
|
||||
*/
|
||||
public static String parseValueToString(Object rootObject, Method method, Object[] args, String spEL) {
|
||||
|
||||
StandardEvaluationContext context = getSpElContext(rootObject, method, args);
|
||||
return parseValueToString(context, spEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 支持 #p0 参数索引的表达式解析
|
||||
* @param rootObject 根对象,method 所在的对象
|
||||
* @param method ,目标方法
|
||||
* @param args 方法入参
|
||||
* @return 解析后的字符串
|
||||
*/
|
||||
public static StandardEvaluationContext getSpElContext(Object rootObject, Method method, Object[] args) {
|
||||
|
||||
String[] paraNameArr = PARAMETER_NAME_DISCOVERER.getParameterNames(method);
|
||||
// SPEL 上下文
|
||||
StandardEvaluationContext context = new MethodBasedEvaluationContext(rootObject, method, args,
|
||||
PARAMETER_NAME_DISCOVERER);
|
||||
// 把方法参数放入 SPEL 上下文中
|
||||
for (int i = 0; i < paraNameArr.length; i++) {
|
||||
context.setVariable(paraNameArr[i], args[i]);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
public static String parseValueToString(StandardEvaluationContext context, String spEL) {
|
||||
return PARSER.parseExpression(spEL).getValue(context, String.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ import java.lang.annotation.*;
|
||||
/**
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2019/8/31 16:08
|
||||
* 利用Aop, 在方法执行后执行缓存删除操作
|
||||
* @date 2019/8/31 16:08 利用Aop, 在方法执行后执行缓存删除操作
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -14,15 +13,14 @@ import java.lang.annotation.*;
|
||||
@MetaCacheAnnotation
|
||||
public @interface CacheDel {
|
||||
|
||||
/**
|
||||
* redis 存储的Key名
|
||||
*/
|
||||
String key();
|
||||
/**
|
||||
* redis 存储的Key名
|
||||
*/
|
||||
String key();
|
||||
|
||||
/**
|
||||
* 如果需要在key 后面拼接参数
|
||||
* 则传入一个拼接数据的 SpEL 表达式
|
||||
*/
|
||||
String keyJoint() default "";
|
||||
/**
|
||||
* 如果需要在key 后面拼接参数 则传入一个拼接数据的 SpEL 表达式
|
||||
*/
|
||||
String keyJoint() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ import java.lang.annotation.*;
|
||||
/**
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2019/8/31 16:08
|
||||
* 利用Aop, 在方法执行后执行缓存put操作
|
||||
* 将方法的返回值置入缓存中,若方法返回null,则会默认置入一个nullValue
|
||||
* @date 2019/8/31 16:08 利用Aop, 在方法执行后执行缓存put操作 将方法的返回值置入缓存中,若方法返回null,则会默认置入一个nullValue
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -15,24 +13,19 @@ import java.lang.annotation.*;
|
||||
@MetaCacheAnnotation
|
||||
public @interface CachePut {
|
||||
|
||||
/**
|
||||
* redis 存储的Key名
|
||||
*/
|
||||
String key();
|
||||
/**
|
||||
* redis 存储的Key名
|
||||
*/
|
||||
String key();
|
||||
|
||||
/**
|
||||
* 如果需要在key 后面拼接参数
|
||||
* 则传入一个拼接数据的 SpEL 表达式
|
||||
*/
|
||||
String keyJoint() default "";
|
||||
|
||||
/**
|
||||
* 超时时间(S)
|
||||
* ttl = 0 使用全局配置值
|
||||
* ttl < 0 : 不超时
|
||||
* ttl > 0 : 使用此超时间
|
||||
*/
|
||||
long ttl() default 0;
|
||||
/**
|
||||
* 如果需要在key 后面拼接参数 则传入一个拼接数据的 SpEL 表达式
|
||||
*/
|
||||
String keyJoint() default "";
|
||||
|
||||
/**
|
||||
* 超时时间(S) ttl = 0 使用全局配置值 ttl < 0 : 不超时 ttl > 0 : 使用此超时间
|
||||
*/
|
||||
long ttl() default 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ import java.lang.annotation.*;
|
||||
/**
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2019/8/31 16:08
|
||||
* 利用Aop, 在方法调用前先查询缓存
|
||||
* 若缓存中没有数据,则调用方法本身,并将方法返回值放置入缓存中
|
||||
* @date 2019/8/31 16:08 利用Aop, 在方法调用前先查询缓存 若缓存中没有数据,则调用方法本身,并将方法返回值放置入缓存中
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -15,24 +13,19 @@ import java.lang.annotation.*;
|
||||
@MetaCacheAnnotation
|
||||
public @interface Cached {
|
||||
|
||||
/**
|
||||
* redis 存储的Key名
|
||||
*/
|
||||
String key();
|
||||
/**
|
||||
* redis 存储的Key名
|
||||
*/
|
||||
String key();
|
||||
|
||||
/**
|
||||
* 如果需要在key 后面拼接参数
|
||||
* 则传入一个拼接数据的 SpEL 表达式
|
||||
*/
|
||||
String keyJoint() default "";
|
||||
|
||||
/**
|
||||
* 超时时间(S)
|
||||
* ttl = 0 使用全局配置值
|
||||
* ttl < 0 : 不超时
|
||||
* ttl > 0 : 使用此超时间
|
||||
*/
|
||||
long ttl() default 0;
|
||||
/**
|
||||
* 如果需要在key 后面拼接参数 则传入一个拼接数据的 SpEL 表达式
|
||||
*/
|
||||
String keyJoint() default "";
|
||||
|
||||
/**
|
||||
* 超时时间(S) ttl = 0 使用全局配置值 ttl < 0 : 不超时 ttl > 0 : 使用此超时间
|
||||
*/
|
||||
long ttl() default 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ import java.lang.annotation.*;
|
||||
/**
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2019/8/31 16:08
|
||||
* 用于标识切点的元注解
|
||||
* @date 2019/8/31 16:08 用于标识切点的元注解
|
||||
*/
|
||||
@Target(ElementType.ANNOTATION_TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
||||
@@ -10,30 +10,27 @@ import org.aspectj.lang.ProceedingJoinPoint;
|
||||
*/
|
||||
public abstract class AbstractCacheOps {
|
||||
|
||||
public AbstractCacheOps(ProceedingJoinPoint joinPoint){
|
||||
this.joinPoint = joinPoint;
|
||||
}
|
||||
public AbstractCacheOps(ProceedingJoinPoint joinPoint) {
|
||||
this.joinPoint = joinPoint;
|
||||
}
|
||||
|
||||
private final ProceedingJoinPoint joinPoint;
|
||||
private final ProceedingJoinPoint joinPoint;
|
||||
|
||||
/**
|
||||
* 织入方法
|
||||
*
|
||||
* @return ProceedingJoinPoint
|
||||
*/
|
||||
public ProceedingJoinPoint joinPoint() {
|
||||
return joinPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查缓存数据是否是空值
|
||||
*
|
||||
* @param cacheData
|
||||
* @return
|
||||
*/
|
||||
public boolean nullValue(Object cacheData) {
|
||||
return CachePropertiesHolder.nullValue().equals(cacheData);
|
||||
}
|
||||
/**
|
||||
* 织入方法
|
||||
* @return ProceedingJoinPoint
|
||||
*/
|
||||
public ProceedingJoinPoint joinPoint() {
|
||||
return joinPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查缓存数据是否是空值
|
||||
* @param cacheData
|
||||
* @return
|
||||
*/
|
||||
public boolean nullValue(Object cacheData) {
|
||||
return CachePropertiesHolder.nullValue().equals(cacheData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,20 +10,19 @@ import org.aspectj.lang.ProceedingJoinPoint;
|
||||
*/
|
||||
public class CacheDelOps extends AbstractCacheOps {
|
||||
|
||||
/**
|
||||
* 删除缓存数据
|
||||
*
|
||||
* @return VoidMethod
|
||||
*/
|
||||
private VoidMethod cacheDel;
|
||||
/**
|
||||
* 删除缓存数据
|
||||
* @return VoidMethod
|
||||
*/
|
||||
private VoidMethod cacheDel;
|
||||
|
||||
public CacheDelOps(ProceedingJoinPoint joinPoint, VoidMethod cacheDel) {
|
||||
super(joinPoint);
|
||||
this.cacheDel = cacheDel;
|
||||
}
|
||||
public CacheDelOps(ProceedingJoinPoint joinPoint, VoidMethod cacheDel) {
|
||||
super(joinPoint);
|
||||
this.cacheDel = cacheDel;
|
||||
}
|
||||
|
||||
public VoidMethod cacheDel() {
|
||||
return cacheDel;
|
||||
}
|
||||
public VoidMethod cacheDel() {
|
||||
return cacheDel;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,20 +11,19 @@ import java.util.function.Consumer;
|
||||
*/
|
||||
public class CachePutOps extends AbstractCacheOps {
|
||||
|
||||
public CachePutOps(ProceedingJoinPoint joinPoint, Consumer<Object> cachePut) {
|
||||
super(joinPoint);
|
||||
this.cachePut = cachePut;
|
||||
}
|
||||
public CachePutOps(ProceedingJoinPoint joinPoint, Consumer<Object> cachePut) {
|
||||
super(joinPoint);
|
||||
this.cachePut = cachePut;
|
||||
}
|
||||
|
||||
/**
|
||||
* 向缓存写入数据
|
||||
*
|
||||
* @return Consumer
|
||||
*/
|
||||
private Consumer<Object> cachePut;
|
||||
/**
|
||||
* 向缓存写入数据
|
||||
* @return Consumer
|
||||
*/
|
||||
private Consumer<Object> cachePut;
|
||||
|
||||
public Consumer<Object> cachePut() {
|
||||
return cachePut;
|
||||
}
|
||||
|
||||
public Consumer<Object> cachePut() {
|
||||
return cachePut;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,62 +13,60 @@ import java.util.function.Supplier;
|
||||
*/
|
||||
public class CachedOps extends AbstractCacheOps {
|
||||
|
||||
/**
|
||||
* 基本构造函数
|
||||
* @param joinPoint 织入方法
|
||||
* @param lockKey 分布式锁key
|
||||
* @param cacheQuery 查询缓存函数
|
||||
* @param cachePut 更新缓存函数
|
||||
* @param returnType 返回数据类型
|
||||
*/
|
||||
public CachedOps(ProceedingJoinPoint joinPoint, String lockKey,
|
||||
Supplier<String> cacheQuery, Consumer<Object> cachePut, Type returnType) {
|
||||
super(joinPoint);
|
||||
this.lockKey = lockKey;
|
||||
this.cacheQuery = cacheQuery;
|
||||
this.cachePut = cachePut;
|
||||
this.returnType = returnType;
|
||||
}
|
||||
/**
|
||||
* 基本构造函数
|
||||
* @param joinPoint 织入方法
|
||||
* @param lockKey 分布式锁key
|
||||
* @param cacheQuery 查询缓存函数
|
||||
* @param cachePut 更新缓存函数
|
||||
* @param returnType 返回数据类型
|
||||
*/
|
||||
public CachedOps(ProceedingJoinPoint joinPoint, String lockKey, Supplier<String> cacheQuery,
|
||||
Consumer<Object> cachePut, Type returnType) {
|
||||
super(joinPoint);
|
||||
this.lockKey = lockKey;
|
||||
this.cacheQuery = cacheQuery;
|
||||
this.cachePut = cachePut;
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据类型
|
||||
*/
|
||||
private Type returnType;
|
||||
/**
|
||||
* 数据类型
|
||||
*/
|
||||
private Type returnType;
|
||||
|
||||
/**
|
||||
* 缓存分布式锁的key
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
private String lockKey;
|
||||
/**
|
||||
* 缓存分布式锁的key
|
||||
* @return String
|
||||
*/
|
||||
private String lockKey;
|
||||
|
||||
/**
|
||||
* 从Redis中获取缓存数据的操作
|
||||
*
|
||||
* @return Supplier
|
||||
*/
|
||||
private Supplier<String> cacheQuery;
|
||||
/**
|
||||
* 从Redis中获取缓存数据的操作
|
||||
* @return Supplier
|
||||
*/
|
||||
private Supplier<String> cacheQuery;
|
||||
|
||||
/**
|
||||
* 向缓存写入数据
|
||||
*
|
||||
* @return Consumer
|
||||
*/
|
||||
private Consumer<Object> cachePut;
|
||||
/**
|
||||
* 向缓存写入数据
|
||||
* @return Consumer
|
||||
*/
|
||||
private Consumer<Object> cachePut;
|
||||
|
||||
public Supplier<String> cacheQuery() {
|
||||
return cacheQuery;
|
||||
}
|
||||
public Supplier<String> cacheQuery() {
|
||||
return cacheQuery;
|
||||
}
|
||||
|
||||
public Consumer<Object> cachePut() {
|
||||
return cachePut;
|
||||
}
|
||||
public Consumer<Object> cachePut() {
|
||||
return cachePut;
|
||||
}
|
||||
|
||||
public Type returnType() {
|
||||
return returnType;
|
||||
}
|
||||
public Type returnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
public String lockKey() {
|
||||
return lockKey;
|
||||
}
|
||||
|
||||
public String lockKey() {
|
||||
return lockKey;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,30 +3,28 @@ package com.hccake.ballcat.common.redis.operation;
|
||||
/**
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2019/9/2 20:50
|
||||
* 对缓存的几种操作类型
|
||||
* @date 2019/9/2 20:50 对缓存的几种操作类型
|
||||
*/
|
||||
public enum OpType {
|
||||
|
||||
/**
|
||||
* 无缓存,直接执行原始方法
|
||||
*/
|
||||
ORIGINAL,
|
||||
/**
|
||||
* 无缓存,直接执行原始方法
|
||||
*/
|
||||
ORIGINAL,
|
||||
|
||||
/**
|
||||
* 先查询缓存,如果有则直接返回
|
||||
* 若没有,则执行目标方法,获取返回值后存入缓存
|
||||
*/
|
||||
CACHED,
|
||||
/**
|
||||
* 先查询缓存,如果有则直接返回 若没有,则执行目标方法,获取返回值后存入缓存
|
||||
*/
|
||||
CACHED,
|
||||
|
||||
/**
|
||||
* 执行目标方法后,获取返回值存入缓存
|
||||
*/
|
||||
PUT,
|
||||
/**
|
||||
* 执行目标方法后,获取返回值存入缓存
|
||||
*/
|
||||
PUT,
|
||||
|
||||
/**
|
||||
* 执行目标方法后,删除缓存
|
||||
*/
|
||||
DEL;
|
||||
/**
|
||||
* 执行目标方法后,删除缓存
|
||||
*/
|
||||
DEL;
|
||||
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@ package com.hccake.ballcat.common.redis.operation.function;
|
||||
@FunctionalInterface
|
||||
public interface ResultMethod<T> {
|
||||
|
||||
/**
|
||||
* 执行并返回一个结果
|
||||
* @return
|
||||
*/
|
||||
T run();
|
||||
/**
|
||||
* 执行并返回一个结果
|
||||
* @return
|
||||
*/
|
||||
T run();
|
||||
|
||||
}
|
||||
|
||||
@@ -8,8 +8,9 @@ package com.hccake.ballcat.common.redis.operation.function;
|
||||
@FunctionalInterface
|
||||
public interface VoidMethod {
|
||||
|
||||
/**
|
||||
* 只执行 无返回值
|
||||
*/
|
||||
void run();
|
||||
/**
|
||||
* 只执行 无返回值
|
||||
*/
|
||||
void run();
|
||||
|
||||
}
|
||||
|
||||
@@ -14,52 +14,48 @@ import java.lang.reflect.Type;
|
||||
*/
|
||||
public interface CacheSerializer {
|
||||
|
||||
/**
|
||||
* 序列化方法
|
||||
*
|
||||
* @param cacheData
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
String serialize(Object cacheData) throws IOException;
|
||||
/**
|
||||
* 序列化方法
|
||||
* @param cacheData
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
String serialize(Object cacheData) throws IOException;
|
||||
|
||||
/**
|
||||
* 反序列化方法
|
||||
* @param cacheData
|
||||
* @param type
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
Object deserialize(String cacheData, Type type) throws IOException;
|
||||
|
||||
/**
|
||||
* 反序列化方法
|
||||
*
|
||||
* @param cacheData
|
||||
* @param type
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
Object deserialize(String cacheData, Type type) throws IOException;
|
||||
/**
|
||||
* Type转JavaType
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public static JavaType getJavaType(Type type) {
|
||||
// 判断是否带有泛型
|
||||
if (type instanceof ParameterizedType) {
|
||||
Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
|
||||
// 获取泛型类型
|
||||
Class rowClass = (Class) ((ParameterizedType) type).getRawType();
|
||||
|
||||
JavaType[] javaTypes = new JavaType[actualTypeArguments.length];
|
||||
|
||||
/**
|
||||
* Type转JavaType
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public static JavaType getJavaType(Type type) {
|
||||
//判断是否带有泛型
|
||||
if (type instanceof ParameterizedType) {
|
||||
Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
|
||||
//获取泛型类型
|
||||
Class rowClass = (Class) ((ParameterizedType) type).getRawType();
|
||||
|
||||
JavaType[] javaTypes = new JavaType[actualTypeArguments.length];
|
||||
|
||||
for (int i = 0; i < actualTypeArguments.length; i++) {
|
||||
//泛型也可能带有泛型,递归获取
|
||||
javaTypes[i] = getJavaType(actualTypeArguments[i]);
|
||||
}
|
||||
return TypeFactory.defaultInstance().constructParametricType(rowClass, javaTypes);
|
||||
} else {
|
||||
//简单类型直接用该类构建JavaType
|
||||
Class cla = (Class) type;
|
||||
return TypeFactory.defaultInstance().constructParametricType(cla, new JavaType[0]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < actualTypeArguments.length; i++) {
|
||||
// 泛型也可能带有泛型,递归获取
|
||||
javaTypes[i] = getJavaType(actualTypeArguments[i]);
|
||||
}
|
||||
return TypeFactory.defaultInstance().constructParametricType(rowClass, javaTypes);
|
||||
}
|
||||
else {
|
||||
// 简单类型直接用该类构建JavaType
|
||||
Class cla = (Class) type;
|
||||
return TypeFactory.defaultInstance().constructParametricType(cla, new JavaType[0]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,32 +12,31 @@ import java.lang.reflect.Type;
|
||||
* @date 2019/9/9 11:07
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class JacksonSerializer implements CacheSerializer{
|
||||
private final ObjectMapper objectMapper;
|
||||
public class JacksonSerializer implements CacheSerializer {
|
||||
|
||||
/**
|
||||
* 反序列化方法
|
||||
*
|
||||
* @param cacheData 缓存中的数据
|
||||
* @param type 反序列化目标类型
|
||||
* @return 反序列化后的对象
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
@Override
|
||||
public Object deserialize(String cacheData, Type type) throws IOException {
|
||||
return objectMapper.readValue(cacheData, CacheSerializer.getJavaType(type));
|
||||
}
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* 序列化方法
|
||||
*
|
||||
* @param cacheData 待缓存的数据
|
||||
* @return 序列化后的数据
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
@Override
|
||||
public String serialize(Object cacheData) throws IOException {
|
||||
return objectMapper.writeValueAsString(cacheData);
|
||||
}
|
||||
/**
|
||||
* 反序列化方法
|
||||
* @param cacheData 缓存中的数据
|
||||
* @param type 反序列化目标类型
|
||||
* @return 反序列化后的对象
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
@Override
|
||||
public Object deserialize(String cacheData, Type type) throws IOException {
|
||||
return objectMapper.readValue(cacheData, CacheSerializer.getJavaType(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列化方法
|
||||
* @param cacheData 待缓存的数据
|
||||
* @return 序列化后的数据
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
@Override
|
||||
public String serialize(Object cacheData) throws IOException {
|
||||
return objectMapper.writeValueAsString(cacheData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,42 +6,45 @@ import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer
|
||||
/**
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2020/3/27 22:57
|
||||
* 自定义Key序列化工具,添加全局key前缀
|
||||
* @date 2020/3/27 22:57 自定义Key序列化工具,添加全局key前缀
|
||||
*/
|
||||
@Slf4j
|
||||
public class PrefixJdkRedisSerializer extends JdkSerializationRedisSerializer {
|
||||
private final String prefix;
|
||||
private final boolean enable;
|
||||
|
||||
public PrefixJdkRedisSerializer(String prefix) {
|
||||
this.prefix = prefix;
|
||||
this.enable = prefix != null && !"".equals(prefix);
|
||||
}
|
||||
private final String prefix;
|
||||
|
||||
@Override
|
||||
public Object deserialize(byte[] bytes) {
|
||||
Object origin = super.deserialize(bytes);
|
||||
if (enable && origin instanceof String) {
|
||||
String originKey = (String) origin;
|
||||
// 如果有全局前缀,则需要删除
|
||||
if (originKey.startsWith(prefix)) {
|
||||
originKey = originKey.substring(prefix.length());
|
||||
}
|
||||
return originKey;
|
||||
}else {
|
||||
return origin;
|
||||
}
|
||||
}
|
||||
private final boolean enable;
|
||||
|
||||
@Override
|
||||
public byte[] serialize(Object object) {
|
||||
if (enable && object instanceof String) {
|
||||
String key = prefix + object;
|
||||
return super.serialize(key);
|
||||
} else {
|
||||
return super.serialize(object);
|
||||
}
|
||||
}
|
||||
public PrefixJdkRedisSerializer(String prefix) {
|
||||
this.prefix = prefix;
|
||||
this.enable = prefix != null && !"".equals(prefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object deserialize(byte[] bytes) {
|
||||
Object origin = super.deserialize(bytes);
|
||||
if (enable && origin instanceof String) {
|
||||
String originKey = (String) origin;
|
||||
// 如果有全局前缀,则需要删除
|
||||
if (originKey.startsWith(prefix)) {
|
||||
originKey = originKey.substring(prefix.length());
|
||||
}
|
||||
return originKey;
|
||||
}
|
||||
else {
|
||||
return origin;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(Object object) {
|
||||
if (enable && object instanceof String) {
|
||||
String key = prefix + object;
|
||||
return super.serialize(key);
|
||||
}
|
||||
else {
|
||||
return super.serialize(object);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,35 +8,37 @@ import java.nio.charset.StandardCharsets;
|
||||
/**
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2020/3/27 22:57
|
||||
* 自定义Key序列化工具,添加全局key前缀
|
||||
* @date 2020/3/27 22:57 自定义Key序列化工具,添加全局key前缀
|
||||
*/
|
||||
@Slf4j
|
||||
public class PrefixStringRedisSerializer extends StringRedisSerializer {
|
||||
private final String prefix;
|
||||
private final boolean enable;
|
||||
public class PrefixStringRedisSerializer extends StringRedisSerializer {
|
||||
|
||||
public PrefixStringRedisSerializer(String prefix) {
|
||||
super(StandardCharsets.UTF_8);
|
||||
this.prefix = prefix;
|
||||
this.enable = prefix != null && !"".equals(prefix);
|
||||
}
|
||||
private final String prefix;
|
||||
|
||||
@Override
|
||||
public String deserialize(byte[] bytes) {
|
||||
String originKey = super.deserialize(bytes);
|
||||
// 如果有全局前缀,则需要删除
|
||||
if (enable && originKey != null && originKey.startsWith(prefix)) {
|
||||
originKey = originKey.substring(prefix.length());
|
||||
}
|
||||
return originKey;
|
||||
}
|
||||
private final boolean enable;
|
||||
|
||||
public PrefixStringRedisSerializer(String prefix) {
|
||||
super(StandardCharsets.UTF_8);
|
||||
this.prefix = prefix;
|
||||
this.enable = prefix != null && !"".equals(prefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deserialize(byte[] bytes) {
|
||||
String originKey = super.deserialize(bytes);
|
||||
// 如果有全局前缀,则需要删除
|
||||
if (enable && originKey != null && originKey.startsWith(prefix)) {
|
||||
originKey = originKey.substring(prefix.length());
|
||||
}
|
||||
return originKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(String string) {
|
||||
if (enable && string != null) {
|
||||
string = prefix + string;
|
||||
}
|
||||
return super.serialize(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(String string) {
|
||||
if(enable && string != null){
|
||||
string = prefix + string;
|
||||
}
|
||||
return super.serialize(string);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user