主要原理利用spring中的AOP知识。
1 首先先创建2个注解以及枚举值
2 切面。
@Component
@Aspect
public class CacheAspect {
private static CentralLogger logger = CentralLogger.getInstance(CacheAspect.class.getName());
private HashMap<String,HashMap<Object,Object>> cacheMap= new HashMap<>();
@Autowired
private RedisTemplate<String,Object> redisTemplate;
/**
* 缓存切点
* 注意点:缓存key=函数第一个参数
* @author ichangtou_feiyang
* 2018年4月18日 下午5:57:49
* @param point
* @return
* @throws Throwable
*/
@SuppressWarnings("unchecked")
@Around("execution(* com.ichangtou.app.cache.cached..*(..))")
public Object aroundMethod(ProceedingJoinPoint point) throws Throwable {
//System.out.println("切面生效");
String methodName = point.getSignature().getName();
Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();
try {
Method method = point.getSignature().getDeclaringType().getMethod(methodName, parameterTypes);
if (method != null && method.isAnnotationPresent(Cache.class)) {
Cache cache = method.getAnnotation(Cache.class);
String cacheName = cache.name();
Object firstParam = null;
if (point.getArgs().length > 0) {
firstParam = point.getArgs()[0];// 方法上第一个参数
} else {
firstParam = cacheName;
}
if (CacheType.Local.getName().equals(cache.type().getName())) {
// 从容器中取出
if (cacheMap.get(cacheName) == null) {
this.putData(cacheMap, cacheName, new HashMap<>());
}
// 方法的第一个参数(默认第一个参数为缓存的key)
Object result = cacheMap.get(cacheName).get(firstParam);
if (result == null) {
Object inputData = point.proceed();
this.putData(cacheMap.get(cacheName), firstParam, inputData);
return inputData;
}
return result;
} else if (CacheType.Redis.getName().equals(cache.type().getName())) {
Object result = redisTemplate.boundHashOps(cacheName).get(firstParam);
if (result == null) {
Object inputData = point.proceed();
redisTemplate.opsForHash().put(cacheName, firstParam, inputData);
return inputData;
}
return result;
}
}
return point.proceed();
} catch (Exception e) {
logger.exception(e);
logger.error("加载缓存异常!!!:"+methodName);
return null;
}
}
/**
* 将对应name的缓存置为null
* @author ichangtou_feiyang
* 2018年4月18日 下午6:07:55
* @param point
*/
@SuppressWarnings("unchecked")
@Before("execution(* com.ichangtou.app.cache.cached..*(..))")
public void beforeMethod(JoinPoint point){
String methodName = point.getSignature().getName();
Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();
try {
Method method = point.getSignature().getDeclaringType().getMethod(methodName, parameterTypes);
if (method != null && method.isAnnotationPresent(FlushCache.class)) {
FlushCache flush = method.getAnnotation(FlushCache.class);
String cacheName = flush.name();
if(CacheType.Local.getName().equals(flush.type().getName())){
cacheMap.put(cacheName, null);
System.out.println("清除了缓存:"+cacheName);
}else if(CacheType.Redis.getName().equals(flush.type())){
redisTemplate.delete(cacheName);
}
}
} catch (Exception e) {
logger.exception(e);
logger.error("清除缓存异常!!!:"+methodName);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private void putData(HashMap map,Object key,Object value){
synchronized (this) {
if (map.get(key) == null) {
//System.out.println("往缓存里增加了数据:"+key);
map.put(key,value);
}
}
}
}
3 写完后,只要在对应扫描包下的方法前加注解即可
4 另,可以写一个父类用来监听spring启动时刻加载缓存,其子类继承并实现loadData方法即可。
@Component
public abstract class BaseCacheLoader implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (event.getApplicationContext().getParent() == null) {
this.loadData();
}
}
public abstract void loadData();
}