结构包:
使用案例:
实现效果:
1、基本并发的本地缓存,基于分布式轻量级锁的redis缓存
2、热缓存(高频访问持续缓存)+快速过期(本地缓存2秒,redis缓存10秒)
3、方法级别缓存清理 (@HybridCache 与@HybridChange 绑定管理缓存 )
扫描二维码关注公众号,回复:
14677396 查看本文章
4、基于HybridType接口的可扩展式作用域,目前已实现:全局、token
5、基于HybridLevel接口的可扩展式缓存处理,目前已实现:本地缓存、redis缓存
核心代码包:
@HybridCache
package com.*.server.live.core.hybridCache;
import com.*.server.live.core.hybridCache.impl.DepthLocal;
import com.*.server.live.core.hybridCache.impl.DepthRedis;
import java.lang.annotation.*;
/**
* 功能描述:多重缓存
* 作者:唐泽齐
* @case @HybridCache(scope = ScopeGlobal.class)
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface HybridCache {
/*缓存深度*/
Class<? extends HybridLevel> depth() default DepthRedis.class;
/*缓存广度*/
Class<? extends HybridType> scope();
}
@HybridCache
@HybridChange
package com.*.server.live.core.hybridCache; import com.*.server.live.core.hybridCache.impl.DepthRedis; import java.lang.annotation.*; /** * 功能描述:多重缓存更新 * 作者:唐泽齐 * @case @HybridChange(clazz = LiveStudioController.class,method = "getStudio",args = {Long.class}) * @case @HybridChange(clazz = LiveStudioController.class,method = "getStudio",args = {}) */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface HybridChange { /*关联类*/ Class<? extends Object> clazz(); /*关联方法*/ String method(); /*关联方法入参类型*/ Class<?>[] args(); } @HybridChange
HybridLevel
package com.*.server.live.core.hybridCache;
import org.aspectj.lang.ProceedingJoinPoint;
import javax.validation.constraints.NotNull;
/**
* 功能描述:多重缓存级别
* 作者:唐泽齐
*/
public interface HybridLevel {
/**
* 缓存
* @param key 缓存key
* @param id 混村ID
* @param o 缓存值
* @param self 是否执行节点
* @param joinPoint 节点
* @return
* @throws Throwable
*/
Object cache(@NotNull String key,@NotNull String id, Object o,@NotNull boolean self,@NotNull ProceedingJoinPoint joinPoint) throws Throwable;
/**
* 清缓存
* @param key 缓存key
* @param self 是否执行节点
* @param joinPoint 节点
* @return
* @throws Throwable
*/
Object del(@NotNull String key,@NotNull boolean self,@NotNull ProceedingJoinPoint joinPoint) throws Throwable;
}
HybridLevel
HybridType
package com.*.server.live.core.hybridCache;
/**
* 功能描述:多重缓存级别
* 作者:唐泽齐
*/
public interface HybridType {
String token();
}
HybridType
HybridCacheInterceptor
package com.*.server.live.core.hybridCache;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.util.Md5Utils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import java.lang.reflect.Method;
/**
* 功能描述:多重缓存接口
* 作者:唐泽齐
*/
@Aspect
@Configuration
public class HybridCacheInterceptor {
@Resource
ApplicationContext applicationContext;
final static String cache = "hybridCache:";
@Around(value = "@annotation(com.*.server.live.core.hybridCache.HybridCache)")
public Object cache(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature ms = (MethodSignature) joinPoint.getSignature();
Method method = ms.getMethod();
HybridCache cacheAnnotation = method.getAnnotation(HybridCache.class);
String key = getCacheKey(method);
String id = getCacheId(method,joinPoint.getArgs());
HybridLevel hybridLevel = applicationContext.getBean(cacheAnnotation.depth());
return hybridLevel.cache(key, id, null, true, joinPoint);
}
@Around(value = "@annotation(com.*.server.live.core.hybridCache.HybridChange)")
public Object del(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature ms = (MethodSignature) joinPoint.getSignature();
Method method = ms.getMethod();
HybridChange cacheAnnotation = method.getAnnotation(HybridChange.class);
try {
Method method1 = cacheAnnotation.clazz().getMethod(cacheAnnotation.method(),cacheAnnotation.args());
HybridCache cache = method1.getAnnotation(HybridCache.class);
String key = getCacheKey(method1);
HybridLevel hybridLevel = applicationContext.getBean(cache.depth());
return hybridLevel.del(key,true, joinPoint);
} catch (Exception e) {
return joinPoint.proceed();
}
}
/*获取缓存key*/
private String getCacheKey(Method method) {
return cache + method.getDeclaringClass().getSimpleName() + ":" + method.getName();
}
;
/*获取缓存id*/
private String getCacheId(Method method,Object[] args) {
HybridCache cacheAnnotation = method.getAnnotation(HybridCache.class);
HybridType hybridType = applicationContext.getBean(cacheAnnotation.scope());
return Md5Utils.getMD5((hybridType.token() + JSON.toJSONString(args)).getBytes());
}
;
}
HybridCacheInterceptor
扩展代码包:
DepthLocal
package com.*.server.live.core.hybridCache.impl;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.*.server.live.core.hybridCache.HybridLevel;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* 功能描述:本地缓存
* 作者:唐泽齐
*/
@Component
public class DepthLocal implements HybridLevel {
/*自带读写锁*/
public volatile static Cache<String, Object> localCache = CacheBuilder.newBuilder().initialCapacity(144).expireAfterAccess(2, TimeUnit.SECONDS).build();
@Override
public Object cache(String key, String id, Object o, boolean search, ProceedingJoinPoint joinPoint) throws Throwable {
String keyId = key + ":" + id;
MethodSignature ms = (MethodSignature) joinPoint.getSignature();
if (search && o == null && (o = localCache.getIfPresent(keyId)) == null) {
synchronized (ms.getMethod()) {
if ((o = localCache.getIfPresent(keyId)) == null) {
o = joinPoint.proceed();
localCache.put(keyId, o);
}
}
}
if (o == null) {
o = localCache.getIfPresent(keyId);
} else {
localCache.put(keyId, o);
}
return o;
}
@Override
public Object del(String key, boolean self, ProceedingJoinPoint joinPoint) throws Throwable {
Object o = null;
if (self) {
o = joinPoint.proceed();
}
localCache.cleanUp();
return o;
}
}
DepthLocal
学习地址:Dpdk/网络协议栈/vpp/OvS/DDos/NFV/虚拟化/高性能专家(免费订阅,永久学习)
【文章福利】需要更多DPDK/SPDK学习资料加群793599096(资料包括C/C++,Linux,golang技术,内核,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,大厂面试题 等)可以自行添加学习交流群点击这里噢~
DepthRedis
package com.*.server.live.core.hybridCache.impl;
import cn.hutool.core.util.RandomUtil;
import com.*.common.redis.service.RedisService;
import com.*.server.live.core.hybridCache.HybridLevel;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 功能描述:redis缓存
* 作者:唐泽齐
*/
@Component
public class DepthRedis implements HybridLevel {
@Resource
private RedisService redisService;
@Resource
private HybridLevel depthLocal;
@Override
public synchronized Object cache(String key, String id, Object o,boolean search, ProceedingJoinPoint joinPoint) throws Throwable {
o = depthLocal.cache(key, id, o,false,joinPoint);
String lock = getLock(key, id);
if(search && o== null && (o=redisService.hget(key , id)) == null ) {
for (;;) {
if(redisService.incr(lock,1l) <= 1l && (o=redisService.hget(key , id)) == null ) {
try {
o = joinPoint.proceed();
redisService.hset(key , id, o, 10l);
} catch (Throwable e) {
throw e;
}finally {
redisService.del(lock);
}
} else {
o = redisService.hget(key , id);
}
if(o == null) {
Thread.sleep(1);
} else {
break;
}
}
}
if (o == null) {
o = redisService.hget(key , id);
} else {
depthLocal.cache(key, id, o,false,joinPoint);
redisService.hset(key , id, o, 10l);
}
return o;
}
@Override
public Object del(String key,boolean self, ProceedingJoinPoint joinPoint) throws Throwable {
Object o = null;
if (self) {
o = joinPoint.proceed();
}
redisService.del(key);
depthLocal.del(key,false,joinPoint);
return o;
}
private String getLock(String key, String id) {
return this.getClass().getSimpleName()+":"+key+":"+id;
}
}
DepthRedis
ScopeGlobal
package com.*.server.live.core.hybridCache.impl;
import com.*.server.live.core.hybridCache.HybridType;
import org.springframework.stereotype.Component;
/**
* 功能描述:全局级别
* 作者:唐泽齐
*/
@Component
public class ScopeGlobal implements HybridType {
@Override
public String token() {
return "";
}
}
ScopeGlobal
ScopeToken
package com.*.server.live.core.hybridCache.impl;
import com.*.common.core.utils.*Util;
import com.*.server.live.core.hybridCache.HybridType;
import org.springframework.stereotype.Component;
/**
* 功能描述:token级别
* 作者:唐泽齐
*/
@Component
public class ScopeToken implements HybridType {
@Override
public String token() {
return *Util.getCurrentTokenValue();
}
}
ScopeToken
问题修复:
1.json问题: 类HybridCacheInterceptor调整使用JSON.toJSON(args).toString()
2.死循环问题:类DepthRedis调整使用
@Override public synchronized Object cache(String key, String id, Object o,boolean search, ProceedingJoinPoint joinPoint) throws Throwable { o = depthLocal.cache(key, id, o,false,joinPoint); final String lock = getLock(key, id); if(search && o== null && (o=redisService.hget(key , id)) == null ) { if(redisService.incr(lock,1l) <= 1l && (o=redisService.hget(key , id)) == null ) { try { o = joinPoint.proceed(); redisService.hset(key , id, o, RandomUtil.randomLong(10l,20l)); } catch (Throwable e) { throw e; }finally { redisService.del(lock); } } else { Thread.sleep(10); o = redisService.hget(key , id); } } if (o == null) { Thread.sleep(10); o = redisService.hget(key , id); } else { depthLocal.cache(key, id, o,false,joinPoint); redisService.hset(key , id, o, 10l); } return o; }
问题修复:
1.取消清除缓存时的常规重试机制:
HybridCacheInterceptor -->
public Object del(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature ms = (MethodSignature) joinPoint.getSignature(); Method method = ms.getMethod(); String updateKey = getCacheKey(method); HybridChange cacheAnnotation = method.getAnnotation(HybridChange.class); Method method1 = cacheAnnotation.clazz().getMethod(cacheAnnotation.method(),cacheAnnotation.args()); HybridCache cache = method1.getAnnotation(HybridCache.class); String key = getCacheKey(method1); try { HybridLevel hybridLevel = applicationContext.getBean(cache.depth()); Object o = hybridLevel.del(key, true, joinPoint); log.info("多级缓存 清除 {}-->{}",updateKey,key); return o; } catch (Exception e) { log.info("多级缓存 清除失败 {}-->{}:{}",updateKey,key,e); throw e; } } 问题修复: 1、分布式情况下缓存死锁问题:
@Override public synchronized Object cache(String key, String id, Object o,boolean search, ProceedingJoinPoint joinPoint) throws Throwable { o = depthLocal.cache(key, id, o,false,joinPoint); final String lock = getLock(key, id); if(search && o== null && (o=redisService.hget(key , id)) == null ) { if(redisService.increx(lock,1l,1l) <= 1l && (o=redisService.hget(key , id)) == null ) { try { o = joinPoint.proceed(); redisService.hset(key , id, o, RandomUtil.randomLong(10l,20l)); } catch (Throwable e) { throw e; }finally { redisService.del(lock); } } else { Thread.sleep(10); o = redisService.hget(key , id); } } if (o == null) { Thread.sleep(10); o = redisService.hget(key , id); } else { depthLocal.cache(key, id, o,false,joinPoint); redisService.hset(key , id, o, 10l); } return o; }