com.github.phantomthief.util.RequestContextCache Maven / Gradle / Ivy
/**
*
*/
package com.github.phantomthief.util;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import com.google.common.collect.Maps;
/**
* @author w.vela
*
* @date 2014年4月11日 下午4:20:24
*/
public class RequestContextCache extends RequestContextHolder
implements IMultiDataAccess {
private static final String PREFIX = "_c";
private static final int THREAD_LOCAL_NAME_LENGTH = 2;
private static final Map> ALL_NAMES = new HashMap<>();
private String uniqueNameForRequestContext;
private final String declareLocation;
private final Set> valueTypes = Collections.synchronizedSet(new HashSet<>());
private final AtomicLong request = new AtomicLong();
private final AtomicLong hit = new AtomicLong();
private final AtomicLong set = new AtomicLong();
private final AtomicLong remove = new AtomicLong();
public RequestContextCache() {
synchronized (RequestContextCache.class) {
String uniqName;
do {
uniqName = PREFIX + RandomStringUtils.randomAlphanumeric(THREAD_LOCAL_NAME_LENGTH);
} while (ALL_NAMES.containsKey(uniqName));
ALL_NAMES.put(uniqName, this);
uniqueNameForRequestContext = uniqName;
}
String location;
try {
location = Thread.currentThread().getStackTrace()[locationCallStackDepth()].toString();
} catch (Throwable e) {
location = null;
}
declareLocation = location;
}
protected int locationCallStackDepth() {
return 2;
}
@SuppressWarnings("unchecked")
private final Map init() {
try {
RequestAttributes attrs = currentRequestAttributes();
ConcurrentHashMap concurrentHashMap = (ConcurrentHashMap) attrs
.getAttribute(uniqueNameForRequestContext, RequestAttributes.SCOPE_REQUEST);
if (concurrentHashMap == null) {
synchronized (attrs) {
concurrentHashMap = (ConcurrentHashMap) attrs.getAttribute(
uniqueNameForRequestContext, RequestAttributes.SCOPE_REQUEST);
if (concurrentHashMap == null) {
concurrentHashMap = new ConcurrentHashMap<>();
attrs.setAttribute(uniqueNameForRequestContext, concurrentHashMap,
RequestAttributes.SCOPE_REQUEST);
}
}
}
return concurrentHashMap;
} catch (IllegalStateException e) {
return null;
}
}
/**
* 请尽量使用
* {@link com.github.phantomthief.util.RequestContextCache#get(Collection)}
*
* @param key
* @return
*/
public V get(K key) {
Map thisCache;
request.addAndGet(1);
if ((thisCache = init()) != null) {
V v = thisCache.get(key);
if (v != null) {
hit.addAndGet(1);
}
return v;
} else {
return null;
}
}
@Override
public Map get(Collection keys) {
Map thisCache;
request.addAndGet(CollectionUtils.size(keys));
if (CollectionUtils.isNotEmpty(keys) && (thisCache = init()) != null) {
Map map = Collections.unmodifiableMap(Maps.filterKeys(thisCache, keys::contains));
hit.addAndGet(map.size());
return map;
} else {
return Collections.emptyMap();
}
}
@Override
public void set(Map dataMap) {
Map thisMap = init();
if (thisMap != null) {
if (MapUtils.isNotEmpty(dataMap)) {
set.addAndGet(CollectionUtils.size(dataMap));
thisMap.putAll(dataMap);
valueTypes.addAll(dataMap.values().stream().filter(Objects::nonNull)
.map(Object::getClass).distinct().collect(Collectors.toList()));
}
}
}
/**
* 请尽量使用
* {@link com.github.phantomthief.util.RequestContextCache#set(Map)}
*
* @param key
* @param value
*/
public void set(K key, V value) {
Map thisMap = init();
if (thisMap != null) {
if (key != null && value != null) {
set.addAndGet(1);
thisMap.put(key, value);
valueTypes.add(value.getClass());
}
}
}
public void remove(K key) {
Map thisMap = init();
if (thisMap != null) {
remove.incrementAndGet();
thisMap.remove(key);
}
}
public final class CacheStats {
public double getHitRate() {
return (double) getHitCount() / getRequestCount();
}
public long getHitCount() {
return hit.get();
}
public long getRequestCount() {
return request.get();
}
public long getSetCount() {
return set.get();
}
public long getRemoveCount() {
return remove.get();
}
public String getDeclareLocation() {
return declareLocation;
}
public Collection> getValueTypes() {
return valueTypes;
}
}
public static final List.CacheStats> getStats() {
synchronized (RequestContextCache.class) {
return ALL_NAMES.values().stream().map(i -> i.new CacheStats())
.collect(Collectors.toList());
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy