
com.alicp.jetcache.anno.method.CacheHandler Maven / Gradle / Ivy
The newest version!
/**
* Created on 13-09-09 15:59
*/
package com.alicp.jetcache.anno.method;
import com.alicp.jetcache.AbstractCache;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.CacheInvokeException;
import com.alicp.jetcache.CacheLoader;
import com.alicp.jetcache.ProxyCache;
import com.alicp.jetcache.anno.support.CacheContext;
import com.alicp.jetcache.anno.support.CacheInvalidateAnnoConfig;
import com.alicp.jetcache.anno.support.CacheUpdateAnnoConfig;
import com.alicp.jetcache.anno.support.CachedAnnoConfig;
import com.alicp.jetcache.anno.support.ConfigMap;
import com.alicp.jetcache.event.CacheLoadEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
/**
* @author huangli
*/
public class CacheHandler implements InvocationHandler {
private static Logger logger = LoggerFactory.getLogger(CacheHandler.class);
private Object src;
private Supplier contextSupplier;
private String[] hiddenPackages;
private ConfigMap configMap;
private static class CacheContextSupport extends CacheContext {
public CacheContextSupport() {
super(null, null, null);
}
static void _enable() {
enable();
}
static void _disable() {
disable();
}
static boolean _isEnabled() {
return isEnabled();
}
}
public CacheHandler(Object src, ConfigMap configMap, Supplier contextSupplier, String[] hiddenPackages) {
this.src = src;
this.configMap = configMap;
this.contextSupplier = contextSupplier;
this.hiddenPackages = hiddenPackages;
}
@Override
public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
CacheInvokeContext context = null;
String sig = ClassUtil.getMethodSig(method);
CacheInvokeConfig cac = configMap.getByMethodInfo(sig);
if (cac != null) {
context = contextSupplier.get();
context.setCacheInvokeConfig(cac);
}
if (context == null) {
return method.invoke(src, args);
} else {
context.setInvoker(() -> method.invoke(src, args));
context.setHiddenPackages(hiddenPackages);
context.setArgs(args);
context.setMethod(method);
return invoke(context);
}
}
public static Object invoke(CacheInvokeContext context) throws Throwable {
if (context.getCacheInvokeConfig().isEnableCacheContext()) {
try {
CacheContextSupport._enable();
return doInvoke(context);
} finally {
CacheContextSupport._disable();
}
} else {
return doInvoke(context);
}
}
private static Object doInvoke(CacheInvokeContext context) throws Throwable {
CacheInvokeConfig cic = context.getCacheInvokeConfig();
CachedAnnoConfig cachedConfig = cic.getCachedAnnoConfig();
if (cachedConfig != null && (cachedConfig.isEnabled() || CacheContextSupport._isEnabled())) {
return invokeWithCached(context);
} else if (cic.getInvalidateAnnoConfigs() != null || cic.getUpdateAnnoConfig() != null) {
return invokeWithInvalidateOrUpdate(context);
} else {
return invokeOrigin(context);
}
}
private static Object invokeWithInvalidateOrUpdate(CacheInvokeContext context) throws Throwable {
Object originResult = invokeOrigin(context);
context.setResult(originResult);
CacheInvokeConfig cic = context.getCacheInvokeConfig();
if (cic.getInvalidateAnnoConfigs() != null) {
doInvalidate(context, cic.getInvalidateAnnoConfigs());
}
CacheUpdateAnnoConfig updateAnnoConfig = cic.getUpdateAnnoConfig();
if (updateAnnoConfig != null) {
doUpdate(context, updateAnnoConfig);
}
return originResult;
}
private static Iterable toIterable(Object obj) {
if (obj.getClass().isArray()) {
if (obj instanceof Object[]) {
return Arrays.asList((Object[]) obj);
} else {
List list = new ArrayList();
int len = Array.getLength(obj);
for (int i = 0; i < len; i++) {
list.add(Array.get(obj, i));
}
return list;
}
} else if (obj instanceof Iterable) {
return (Iterable) obj;
} else {
return null;
}
}
private static void doInvalidate(CacheInvokeContext context, List annoConfig) {
for (CacheInvalidateAnnoConfig config : annoConfig) {
doInvalidate(context, config);
}
}
private static void doInvalidate(CacheInvokeContext context, CacheInvalidateAnnoConfig annoConfig) {
Cache cache = context.getCacheFunction().apply(context, annoConfig);
if (cache == null) {
return;
}
boolean condition = ExpressionUtil.evalCondition(context, annoConfig);
if (!condition) {
return;
}
Object key = ExpressionUtil.evalKey(context, annoConfig);
if (key == null) {
return;
}
if (annoConfig.isMulti()) {
Iterable it = toIterable(key);
if (it == null) {
logger.error("jetcache @CacheInvalidate key is not instance of Iterable or array: " + annoConfig.getDefineMethod());
return;
}
Set keys = new HashSet();
it.forEach(k -> keys.add(k));
cache.removeAll(keys);
} else {
cache.remove(key);
}
}
private static void doUpdate(CacheInvokeContext context, CacheUpdateAnnoConfig updateAnnoConfig) {
Cache cache = context.getCacheFunction().apply(context, updateAnnoConfig);
if (cache == null) {
return;
}
boolean condition = ExpressionUtil.evalCondition(context, updateAnnoConfig);
if (!condition) {
return;
}
Object key = ExpressionUtil.evalKey(context, updateAnnoConfig);
Object value = ExpressionUtil.evalValue(context, updateAnnoConfig);
if (key == null || value == ExpressionUtil.EVAL_FAILED) {
return;
}
if (updateAnnoConfig.isMulti()) {
if (value == null) {
return;
}
Iterable keyIt = toIterable(key);
Iterable valueIt = toIterable(value);
if (keyIt == null) {
logger.error("jetcache @CacheUpdate key is not instance of Iterable or array: " + updateAnnoConfig.getDefineMethod());
return;
}
if (valueIt == null) {
logger.error("jetcache @CacheUpdate value is not instance of Iterable or array: " + updateAnnoConfig.getDefineMethod());
return;
}
List keyList = new ArrayList();
List valueList = new ArrayList();
keyIt.forEach(o -> keyList.add(o));
valueIt.forEach(o -> valueList.add(o));
if (keyList.size() != valueList.size()) {
logger.error("jetcache @CacheUpdate key size not equals with value size: " + updateAnnoConfig.getDefineMethod());
return;
} else {
Map m = new HashMap();
for (int i = 0; i < valueList.size(); i++) {
m.put(keyList.get(i), valueList.get(i));
}
cache.putAll(m);
}
} else {
cache.put(key, value);
}
}
private static Object invokeWithCached(CacheInvokeContext context)
throws Throwable {
CacheInvokeConfig cic = context.getCacheInvokeConfig();
CachedAnnoConfig cac = cic.getCachedAnnoConfig();
Cache cache = context.getCacheFunction().apply(context, cac);
if (cache == null) {
logger.error("no cache with name: " + context.getMethod());
return invokeOrigin(context);
}
Object key = ExpressionUtil.evalKey(context, cic.getCachedAnnoConfig());
if (key == null) {
return loadAndCount(context, cache, key);
}
if (!ExpressionUtil.evalCondition(context, cic.getCachedAnnoConfig())) {
return loadAndCount(context, cache, key);
}
try {
CacheLoader loader = new CacheLoader() {
@Override
public Object load(Object k) throws Throwable {
Object result = invokeOrigin(context);
context.setResult(result);
return result;
}
@Override
public boolean vetoCacheUpdate() {
return !ExpressionUtil.evalPostCondition(context, cic.getCachedAnnoConfig());
}
};
Object result = cache.computeIfAbsent(key, loader);
return result;
} catch (CacheInvokeException e) {
throw e.getCause();
}
}
private static Object loadAndCount(CacheInvokeContext context, Cache cache, Object key) throws Throwable {
long t = System.currentTimeMillis();
Object v = null;
boolean success = false;
try {
v = invokeOrigin(context);
success = true;
} finally {
t = System.currentTimeMillis() - t;
CacheLoadEvent event = new CacheLoadEvent(cache, t, key, v, success);
while (cache instanceof ProxyCache) {
cache = ((ProxyCache) cache).getTargetCache();
}
if (cache instanceof AbstractCache) {
((AbstractCache) cache).notify(event);
}
}
return v;
}
private static Object invokeOrigin(CacheInvokeContext context) throws Throwable {
return context.getInvoker().invoke();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy