mirror of
https://github.com/tiennm99/zfoo.git
synced 2026-05-21 08:25:28 +00:00
perf[storage]:优化配置表模块
1.增加函数式方法引用缓存; 2.移除guava依赖库,减少第三方依赖; 3.优化部分函数式接口;
This commit is contained in:
@@ -15,17 +15,23 @@ package com.zfoo.protocol.util;
|
||||
import com.zfoo.protocol.collection.ArrayUtils;
|
||||
import com.zfoo.protocol.exception.RunException;
|
||||
|
||||
import java.beans.Introspector;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author godotg
|
||||
@@ -41,8 +47,6 @@ public abstract class ClassUtils {
|
||||
public final static String JAR_PROTOCOL = "jar";
|
||||
|
||||
public final static String JAR_URL_SEPARATOR = "!/";
|
||||
private static final Pattern GET_PATTERN = Pattern.compile("^get[A-Z].*");
|
||||
private static final Pattern IS_PATTERN = Pattern.compile("^is[A-Z].*");
|
||||
|
||||
private static ClassLoader systemClassLoader;
|
||||
|
||||
@@ -541,20 +545,4 @@ public abstract class ClassUtils {
|
||||
ClassUtils.class.getClassLoader(),
|
||||
systemClassLoader};
|
||||
}
|
||||
|
||||
/**
|
||||
* 方法名转换为字段名
|
||||
*
|
||||
* @param methodName 方法名
|
||||
* @return
|
||||
*/
|
||||
public static String getFieldName(String methodName) {
|
||||
// 对于非标准变量生成的Get方法这里可以直接抛出异常,或者打印异常日志
|
||||
if (GET_PATTERN.matcher(methodName).matches()) {
|
||||
methodName = methodName.substring(3);
|
||||
} else if (IS_PATTERN.matcher(methodName).matches()) {
|
||||
methodName = methodName.substring(2);
|
||||
}
|
||||
return Introspector.decapitalize(methodName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
<!-- Office document parsing(office文档解析包) -->
|
||||
<poi.version>5.2.3</poi.version>
|
||||
<csv.version>1.10.0</csv.version>
|
||||
<guava.version>32.1.2-jre</guava.version>
|
||||
<java.version>17</java.version>
|
||||
<file.encoding>UTF-8</file.encoding>
|
||||
<!-- maven core plugin(maven核心插件) -->
|
||||
@@ -112,12 +111,6 @@
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ package com.zfoo.storage;
|
||||
|
||||
import com.zfoo.scheduler.util.StopWatch;
|
||||
import com.zfoo.storage.manager.IStorageManager;
|
||||
import com.zfoo.storage.util.support.SerializableFunction;
|
||||
import com.zfoo.storage.util.function.Func1;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -60,12 +60,12 @@ public class StorageContext implements ApplicationListener<ApplicationContextEve
|
||||
return instance.storageManager.getStorage(clazz).getList();
|
||||
}
|
||||
|
||||
public static <K, V> List<V> getIndexes(Class<V> clazz, SerializableFunction<V, ?> function, K indexId) {
|
||||
return instance.storageManager.getStorage(clazz).getIndexes(function, indexId);
|
||||
public static <K, V> List<V> getIndexes(Class<V> clazz, Func1<V, ?> function, K keyId) {
|
||||
return instance.storageManager.getStorage(clazz).getIndexes(function, keyId);
|
||||
}
|
||||
|
||||
public static <K, V> V getUniqueIndex(Class<V> clazz, SerializableFunction<V, ?> function, K indexId) {
|
||||
return instance.storageManager.getStorage(clazz).getUniqueIndex(function, indexId);
|
||||
public static <K, V> V getUniqueIndex(Class<V> clazz, Func1<V, ?> func, K keyId) {
|
||||
return instance.storageManager.getStorage(clazz).getUniqueIndex(func, keyId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,7 +16,11 @@ package com.zfoo.storage.manager;
|
||||
import com.zfoo.protocol.collection.CollectionUtils;
|
||||
import com.zfoo.protocol.exception.ExceptionUtils;
|
||||
import com.zfoo.protocol.exception.RunException;
|
||||
import com.zfoo.protocol.util.*;
|
||||
import com.zfoo.protocol.util.ClassUtils;
|
||||
import com.zfoo.protocol.util.FileUtils;
|
||||
import com.zfoo.protocol.util.GraalVmUtils;
|
||||
import com.zfoo.protocol.util.ReflectionUtils;
|
||||
import com.zfoo.protocol.util.StringUtils;
|
||||
import com.zfoo.storage.StorageContext;
|
||||
import com.zfoo.storage.anno.GraalvmNativeStorage;
|
||||
import com.zfoo.storage.anno.Id;
|
||||
@@ -26,7 +30,7 @@ import com.zfoo.storage.config.StorageConfig;
|
||||
import com.zfoo.storage.interpreter.data.StorageEnum;
|
||||
import com.zfoo.storage.model.IStorage;
|
||||
import com.zfoo.storage.model.StorageDefinition;
|
||||
import com.zfoo.storage.util.support.SerializableFunction;
|
||||
import com.zfoo.storage.util.function.Func1;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
@@ -43,7 +47,13 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.*;
|
||||
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.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -196,14 +206,14 @@ public class StorageManager implements IStorageManager {
|
||||
return (List<T>) storage.getAll();
|
||||
}
|
||||
|
||||
public <T, K> List<T> getIndexes(Class<T> clazz, SerializableFunction<T, ?> function, K indexId) {
|
||||
public <T, K> List<T> getIndexes(Class<T> clazz, Func1<T, ?> func, K indexId) {
|
||||
var storage = getStorage(clazz);
|
||||
return storage.getIndexes(function, indexId);
|
||||
return storage.getIndexes(func, indexId);
|
||||
}
|
||||
|
||||
public <T, UQ> T get(Class<T> clazz, UQ uniqueId) {
|
||||
public <T, UQ> T get(Class<T> clazz, UQ keyId) {
|
||||
IStorage<UQ, T> storage = getStorage(clazz);
|
||||
return storage.get(uniqueId);
|
||||
return storage.get(keyId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -12,10 +12,8 @@
|
||||
|
||||
package com.zfoo.storage.manager;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.zfoo.protocol.collection.CollectionUtils;
|
||||
import com.zfoo.protocol.util.AssertionUtils;
|
||||
import com.zfoo.protocol.util.ClassUtils;
|
||||
import com.zfoo.protocol.util.IOUtils;
|
||||
import com.zfoo.protocol.util.ReflectionUtils;
|
||||
import com.zfoo.protocol.util.StringUtils;
|
||||
@@ -24,7 +22,7 @@ import com.zfoo.storage.model.IStorage;
|
||||
import com.zfoo.storage.model.IdDef;
|
||||
import com.zfoo.storage.model.IndexDef;
|
||||
import com.zfoo.storage.util.LambdaUtils;
|
||||
import com.zfoo.storage.util.support.SerializableFunction;
|
||||
import com.zfoo.storage.util.function.Func1;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import java.io.InputStream;
|
||||
@@ -40,15 +38,15 @@ import java.util.stream.Collectors;
|
||||
* @author godotg
|
||||
*/
|
||||
public class StorageObject<K, V> implements IStorage<K, V> {
|
||||
private ImmutableMap<K, V> dataMap;
|
||||
private Map<K, V> dataMap = new HashMap<>(64);
|
||||
// 非唯一索引
|
||||
protected ImmutableMap<String, Map<Object, List<V>>> indexMap;
|
||||
protected Map<String, Map<Object, List<V>>> indexMap = new HashMap<>(32);
|
||||
// 唯一索引
|
||||
protected ImmutableMap<String, Map<Object, V>> uniqueIndexMap;
|
||||
protected Map<String, Map<Object, V>> uniqueIndexMap = new HashMap<>(16);
|
||||
|
||||
protected Class<?> clazz;
|
||||
protected IdDef idDef;
|
||||
protected ImmutableMap<String, IndexDef> indexDefMap;
|
||||
protected Map<String, IndexDef> indexDefMap;
|
||||
// 当前配置表是否在当前项目中使用,没有被使用的会清除data数据,以达到节省内存的目的
|
||||
protected boolean recycle = true;
|
||||
|
||||
@@ -59,9 +57,11 @@ public class StorageObject<K, V> implements IStorage<K, V> {
|
||||
storage.clazz = resourceClazz;
|
||||
var idDef = IdDef.valueOf(resourceClazz);
|
||||
storage.idDef = idDef;
|
||||
storage.indexDefMap = ImmutableMap.copyOf(IndexDef.createResourceIndexes(resourceClazz));
|
||||
storage.indexDefMap = Collections.unmodifiableMap(IndexDef.createResourceIndexes(resourceClazz));
|
||||
var list = ResourceInterpreter.read(inputStream, resourceClazz, suffix);
|
||||
storage.append(list);
|
||||
for (var object : list) {
|
||||
storage.put(object);
|
||||
}
|
||||
var idType = idDef.getField().getType();
|
||||
if (idType == int.class || idType == Integer.class) {
|
||||
return new StorageInt<>(storage);
|
||||
@@ -159,8 +159,8 @@ public class StorageObject<K, V> implements IStorage<K, V> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K> List<V> getIndexes(SerializableFunction<V, ?> indexFunction, K key) {
|
||||
String indexName = ClassUtils.getFieldName(LambdaUtils.extract(indexFunction).getImplMethodName());
|
||||
public <K> List<V> getIndexes(Func1<V, ?> func, K key) {
|
||||
String indexName = LambdaUtils.getFieldName(func);
|
||||
var indexValues = indexMap.get(indexName);
|
||||
AssertionUtils.notNull(indexValues, "The index of [indexName:{}] does not exist in the static resource [resource:{}]", indexName, clazz.getSimpleName());
|
||||
var values = indexValues.get(key);
|
||||
@@ -172,8 +172,8 @@ public class StorageObject<K, V> implements IStorage<K, V> {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <K, V> V getUniqueIndex(SerializableFunction<V, ?> uniqueIndexFunction, K key) {
|
||||
String uniqueIndexName = ClassUtils.getFieldName(LambdaUtils.extract(uniqueIndexFunction).getImplMethodName());
|
||||
public <K, V> V getUniqueIndex(Func1<V, ?> func, K key) {
|
||||
String uniqueIndexName = LambdaUtils.getFieldName(func);
|
||||
var indexValueMap = uniqueIndexMap.get(uniqueIndexName);
|
||||
AssertionUtils.notNull(indexValueMap, "There is no a unique index for [uniqueIndexName:{}] in the static resource [resource:{}]", uniqueIndexName, clazz.getSimpleName());
|
||||
var value = indexValueMap.get(key);
|
||||
@@ -185,78 +185,36 @@ public class StorageObject<K, V> implements IStorage<K, V> {
|
||||
return dataMap.size();
|
||||
}
|
||||
|
||||
private void append(List<?> values) {
|
||||
ImmutableMap.Builder<K, V> dataMapBuilder = ImmutableMap.builder();
|
||||
Map<String, Map<Object, V>> uniqueIndexMap = new HashMap<>(32);
|
||||
Map<String, Map<Object, List<V>>> indexMap = new HashMap<>(32);
|
||||
for (var value : values) {
|
||||
var key = (K) ReflectionUtils.getField(idDef.getField(), value);
|
||||
|
||||
if (key == null) {
|
||||
throw new RuntimeException("There is an item with an unconfigured id in the static resource");
|
||||
}
|
||||
|
||||
// 添加资源
|
||||
var v = (V) value;
|
||||
dataMapBuilder.put(key, v);
|
||||
|
||||
// 添加索引
|
||||
for (var def : indexDefMap.values()) {
|
||||
// 使用field的名称作为索引的名称
|
||||
var indexKey = def.getField().getName();
|
||||
var indexValue = ReflectionUtils.getField(def.getField(), v);
|
||||
if (def.isUnique()) {// 唯一索引
|
||||
var index = uniqueIndexMap.computeIfAbsent(indexKey, k -> new HashMap<>(8));
|
||||
if (index.put(indexValue, v) != null) {
|
||||
throw new RuntimeException(StringUtils.format("Duplicate unique index [index:{}][value:{}] of static resource [class:{}]", indexKey, indexValue, clazz.getName()));
|
||||
}
|
||||
} else {// 不是唯一索引
|
||||
var index = indexMap.computeIfAbsent(indexKey, k -> new HashMap<>(12));
|
||||
var list = index.computeIfAbsent(indexValue, k -> new ArrayList<>());
|
||||
list.add(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.uniqueIndexMap = ImmutableMap.copyOf(uniqueIndexMap);
|
||||
this.indexMap = ImmutableMap.copyOf(indexMap);
|
||||
this.dataMap = dataMapBuilder.build();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
protected V put(Object value) {
|
||||
public V put(Object value) {
|
||||
@SuppressWarnings("unchecked")
|
||||
var key = (K) ReflectionUtils.getField(idDef.getField(), value);
|
||||
|
||||
if (key == null) {
|
||||
throw new RuntimeException("There is an item with an unconfigured id in the static resource");
|
||||
}
|
||||
|
||||
if (dataMap.containsKey(key)) {
|
||||
throw new RuntimeException(StringUtils.format("Duplicate [id:{}] of static resource [resource:{}]", key, clazz.getSimpleName()));
|
||||
}
|
||||
|
||||
// 添加资源
|
||||
@SuppressWarnings("unchecked")
|
||||
var v = (V) value;
|
||||
var result = dataMap.put(key, v);
|
||||
|
||||
// 添加索引
|
||||
for (var def : indexDefMap.values()) {
|
||||
// 使用field的名称作为索引的名称
|
||||
var indexKey = def.getField().getName();
|
||||
var indexValue = ReflectionUtils.getField(def.getField(), v);
|
||||
if (def.isUnique()) {// 唯一索引
|
||||
var index = uniqueIndexMap.computeIfAbsent(indexKey, k -> new HashMap<>());
|
||||
var index = uniqueIndexMap.computeIfAbsent(indexKey, k -> new HashMap<>(12));
|
||||
if (index.put(indexValue, v) != null) {
|
||||
throw new RuntimeException(StringUtils.format("Duplicate unique index [index:{}][value:{}] of static resource [class:{}]", indexKey, indexValue, clazz.getName()));
|
||||
}
|
||||
} else {// 不是唯一索引
|
||||
var index = indexMap.computeIfAbsent(indexKey, k -> new HashMap<>());
|
||||
var index = indexMap.computeIfAbsent(indexKey, k -> new HashMap<>(32));
|
||||
var list = index.computeIfAbsent(indexValue, k -> new ArrayList<V>());
|
||||
list.add(v);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
package com.zfoo.storage.model;
|
||||
|
||||
import com.zfoo.storage.util.support.SerializableFunction;
|
||||
import com.zfoo.storage.util.function.Func1;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -51,10 +51,10 @@ public interface IStorage<K, V> {
|
||||
IdDef getIdDef();
|
||||
|
||||
@Nullable
|
||||
<K> List<V> getIndexes(SerializableFunction<V, ?> function, K key);
|
||||
<K> List<V> getIndexes(Func1<V, ?> function, K key);
|
||||
|
||||
@Nullable
|
||||
<K, V> V getUniqueIndex(SerializableFunction<V, ?> function, K key);
|
||||
<K, V> V getUniqueIndex(Func1<V, ?> function, K key);
|
||||
|
||||
int size();
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package com.zfoo.storage.util;
|
||||
|
||||
import com.zfoo.storage.util.function.Func1;
|
||||
import com.zfoo.storage.util.support.IdeaProxyLambdaMeta;
|
||||
import com.zfoo.storage.util.support.LambdaMeta;
|
||||
import com.zfoo.storage.util.support.ReflectLambdaMeta;
|
||||
import com.zfoo.storage.util.support.SerializableFunction;
|
||||
import com.zfoo.storage.util.support.SerializedLambda;
|
||||
import com.zfoo.storage.util.support.ShadowLambdaMeta;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
@@ -18,7 +19,7 @@ import java.security.AccessController;
|
||||
* @date 2023/9/12
|
||||
*/
|
||||
public final class LambdaUtils {
|
||||
|
||||
private static final SimpleCache<Class, LambdaMeta> FUNC_CACHE = new SimpleCache<>(64);
|
||||
|
||||
/**
|
||||
* 该缓存可能会在任意不定的时间被清除
|
||||
@@ -27,7 +28,7 @@ public final class LambdaUtils {
|
||||
* @param <T> 类型,被调用的 Function 对象的目标类型
|
||||
* @return 返回解析后的结果
|
||||
*/
|
||||
public static <T> LambdaMeta extract(SerializableFunction<T, ?> func) {
|
||||
public static <T> LambdaMeta extract(Serializable func) {
|
||||
// 1. IDEA 调试模式下 lambda 表达式是一个代理
|
||||
if (func instanceof Proxy) {
|
||||
return new IdeaProxyLambdaMeta((Proxy) func);
|
||||
@@ -52,4 +53,49 @@ public final class LambdaUtils {
|
||||
public static <T extends AccessibleObject> T setAccessible(T object) {
|
||||
return AccessController.doPrivileged(new SetAccessibleAction<>(object));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析lambda表达式,加了缓存。
|
||||
* 该缓存可能会在任意不定的时间被清除
|
||||
*
|
||||
* @param <T> Lambda类型
|
||||
* @param func 需要解析的 lambda 对象(无参方法)
|
||||
* @return 返回解析后的结果
|
||||
*/
|
||||
public static <T> LambdaMeta resolve(Func1<T, ?> func) {
|
||||
return _resolve(func);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取lambda表达式函数(方法)名称
|
||||
*
|
||||
* @param <T> Lambda类型
|
||||
* @param func 函数(无参方法)
|
||||
* @return 函数名称
|
||||
*/
|
||||
public static <T> String getMethodName(Func1<T, ?> func) {
|
||||
return resolve(func).getImplMethodName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取lambda表达式函数(字段)名称
|
||||
*
|
||||
* @param <T> Lambda类型
|
||||
* @param func 函数
|
||||
* @return 字段名称
|
||||
*/
|
||||
public static <T> String getFieldName(Func1<T, ?> func) {
|
||||
return PropertyNamer.methodToProperty(getMethodName(func));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析lambda表达式,加了缓存。
|
||||
* 该缓存可能会在任意不定的时间被清除
|
||||
*
|
||||
* @param func 需要解析的 lambda 对象
|
||||
* @return 返回解析后的结果
|
||||
*/
|
||||
private static <T> LambdaMeta _resolve(Serializable func) {
|
||||
return FUNC_CACHE.get(func.getClass(), () -> extract(func));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.zfoo.storage.util;
|
||||
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Copy from ibatis framework.
|
||||
*
|
||||
* @author Clinton Begin
|
||||
*/
|
||||
public final class PropertyNamer {
|
||||
|
||||
private PropertyNamer() {
|
||||
// Prevent Instantiation of Static Class
|
||||
}
|
||||
|
||||
public static String methodToProperty(String name) {
|
||||
if (name.startsWith("is")) {
|
||||
name = name.substring(2);
|
||||
} else if (name.startsWith("get") || name.startsWith("set")) {
|
||||
name = name.substring(3);
|
||||
}
|
||||
|
||||
if (name.length() == 1 || name.length() > 1 && !Character.isUpperCase(name.charAt(1))) {
|
||||
name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
public static boolean isProperty(String name) {
|
||||
return isGetter(name) || isSetter(name);
|
||||
}
|
||||
|
||||
public static boolean isGetter(String name) {
|
||||
return name.startsWith("get") && name.length() > 3 || name.startsWith("is") && name.length() > 2;
|
||||
}
|
||||
|
||||
public static boolean isSetter(String name) {
|
||||
return name.startsWith("set") && name.length() > 3;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
package com.zfoo.storage.util;
|
||||
|
||||
import com.zfoo.storage.util.function.Func0;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* 简单缓存,无超时实现,默认使用{@link WeakHashMap}实现缓存自动清理
|
||||
*
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
* @author Looly
|
||||
*/
|
||||
public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 池
|
||||
*/
|
||||
private final Map<K, V> cache;
|
||||
// 乐观读写锁
|
||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
/**
|
||||
* 写的时候每个key一把锁,降低锁的粒度
|
||||
*/
|
||||
protected final Map<K, Lock> keyLockMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 构造,默认使用{@link WeakHashMap}实现缓存自动清理
|
||||
*/
|
||||
public SimpleCache() {
|
||||
this(32);
|
||||
}
|
||||
|
||||
public SimpleCache(int initialCapacity) {
|
||||
this(new WeakHashMap<>(initialCapacity));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
* <p>
|
||||
* 通过自定义Map初始化,可以自定义缓存实现。<br>
|
||||
* 比如使用{@link WeakHashMap}则会自动清理key,使用HashMap则不会清理<br>
|
||||
* 同时,传入的Map对象也可以自带初始化的键值对,防止在get时创建
|
||||
* </p>
|
||||
*
|
||||
* @param initMap 初始Map,用于定义Map类型
|
||||
*/
|
||||
public SimpleCache(Map<K, V> initMap) {
|
||||
this.cache = initMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存池中查找值
|
||||
*
|
||||
* @param key 键
|
||||
* @return 值
|
||||
*/
|
||||
public V get(K key) {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
return cache.get(key);
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象
|
||||
*
|
||||
* @param key 键
|
||||
* @param supplier 如果不存在回调方法,用于生产值对象
|
||||
* @return 值对象
|
||||
*/
|
||||
public V get(K key, Func0<V> supplier) {
|
||||
return get(key, null, supplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象
|
||||
*
|
||||
* @param key 键
|
||||
* @param validPredicate 检查结果对象是否可用,如是否断开连接等
|
||||
* @param supplier 如果不存在回调方法或结果不可用,用于生产值对象
|
||||
* @return 值对象
|
||||
*/
|
||||
public V get(K key, Predicate<V> validPredicate, Func0<V> supplier) {
|
||||
V v = get(key);
|
||||
if (null == v && null != supplier) {
|
||||
//每个key单独获取一把锁,降低锁的粒度提高并发能力,see pr#1385@Github
|
||||
final Lock keyLock = keyLockMap.computeIfAbsent(key, k -> new ReentrantLock());
|
||||
keyLock.lock();
|
||||
try {
|
||||
// 双重检查,防止在竞争锁的过程中已经有其它线程写入
|
||||
v = cache.get(key);
|
||||
if (null == v || (null != validPredicate && false == validPredicate.test(v))) {
|
||||
try {
|
||||
v = supplier.call();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
put(key, v);
|
||||
}
|
||||
} finally {
|
||||
keyLock.unlock();
|
||||
keyLockMap.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* 放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return 值
|
||||
*/
|
||||
public V put(K key, V value) {
|
||||
// 独占写锁
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
cache.put(key, value);
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @return 移除的值
|
||||
*/
|
||||
public V remove(K key) {
|
||||
// 独占写锁
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
return cache.remove(key);
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空缓存池
|
||||
*/
|
||||
public void clear() {
|
||||
// 独占写锁
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
this.cache.clear();
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<K, V>> iterator() {
|
||||
return this.cache.entrySet().iterator();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.zfoo.storage.util.function;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 函数对象<br>
|
||||
* 接口灵感来自于<a href="http://actframework.org/">ActFramework</a><br>
|
||||
* 一个函数接口代表一个一个函数,用于包装一个函数为对象<br>
|
||||
* 在JDK8之前,Java的函数并不能作为参数传递,也不能作为返回值存在,此接口用于将一个函数包装成为一个对象,从而传递对象
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
* @param <P> 参数类型
|
||||
* @param <R> 返回值类型
|
||||
* @since 3.1.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Func<P, R> extends Serializable {
|
||||
/**
|
||||
* 执行函数
|
||||
*
|
||||
* @param parameters 参数列表
|
||||
* @return 函数执行结果
|
||||
* @throws Exception 自定义异常
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
R call(P... parameters) throws Exception;
|
||||
|
||||
/**
|
||||
* 执行函数,异常包装为RuntimeException
|
||||
*
|
||||
* @param parameters 参数列表
|
||||
* @return 函数执行结果
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default R callWithRuntimeException(P... parameters){
|
||||
try {
|
||||
return call(parameters);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.zfoo.storage.util.function;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 无参数的函数对象<br>
|
||||
* 接口灵感来自于<a href="http://actframework.org/">ActFramework</a><br>
|
||||
* 一个函数接口代表一个一个函数,用于包装一个函数为对象<br>
|
||||
* 在JDK8之前,Java的函数并不能作为参数传递,也不能作为返回值存在,此接口用于将一个函数包装成为一个对象,从而传递对象
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
* @param <R> 返回值类型
|
||||
* @since 4.5.2
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Func0<R> extends Serializable {
|
||||
/**
|
||||
* 执行函数
|
||||
*
|
||||
* @return 函数执行结果
|
||||
* @throws Exception 自定义异常
|
||||
*/
|
||||
R call() throws Exception;
|
||||
|
||||
/**
|
||||
* 执行函数,异常包装为RuntimeException
|
||||
*
|
||||
* @return 函数执行结果
|
||||
* @since 5.3.6
|
||||
*/
|
||||
default R callWithRuntimeException(){
|
||||
try {
|
||||
return call();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.zfoo.storage.util.function;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 只有一个参数的函数对象<br>
|
||||
* 接口灵感来自于<a href="http://actframework.org/">ActFramework</a><br>
|
||||
* 一个函数接口代表一个一个函数,用于包装一个函数为对象<br>
|
||||
* 在JDK8之前,Java的函数并不能作为参数传递,也不能作为返回值存在,此接口用于将一个函数包装成为一个对象,从而传递对象
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
* @param <P> 参数类型
|
||||
* @param <R> 返回值类型
|
||||
* @since 4.2.2
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Func1<P, R> extends Serializable {
|
||||
|
||||
/**
|
||||
* 执行函数
|
||||
*
|
||||
* @param parameter 参数
|
||||
* @return 函数执行结果
|
||||
* @throws Exception 自定义异常
|
||||
*/
|
||||
R call(P parameter) throws Exception;
|
||||
|
||||
/**
|
||||
* 执行函数,异常包装为RuntimeException
|
||||
*
|
||||
* @param parameter 参数
|
||||
* @return 函数执行结果
|
||||
* @since 5.3.6
|
||||
*/
|
||||
default R callWithRuntimeException(P parameter){
|
||||
try {
|
||||
return call(parameter);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.zfoo.storage.util.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 支持序列化的 Function
|
||||
*
|
||||
* @author veione
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SerializableFunction<T, R> extends Function<T, R>, Serializable {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.zfoo.storage;
|
||||
|
||||
import com.zfoo.storage.resource.StudentResource;
|
||||
import com.zfoo.storage.util.LambdaUtils;
|
||||
import com.zfoo.storage.util.function.Func1;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author veione
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public class TestLambdaFunctionCache {
|
||||
|
||||
@Test
|
||||
public void testFunctionCache() {
|
||||
Func1<StudentResource, Object> nameFunc = StudentResource::getName;
|
||||
System.out.println(LambdaUtils.getMethodName(nameFunc));
|
||||
System.out.println(LambdaUtils.getMethodName(nameFunc));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.zfoo.storage;
|
||||
|
||||
import com.zfoo.storage.util.PropertyNamer;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author veione
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public class TestPropertyNamer {
|
||||
|
||||
@Test
|
||||
public void testPropertyName() {
|
||||
//前三种主要用于普通的POJO,第四种用于是record类型,方法名就是属性名
|
||||
String getName = PropertyNamer.methodToProperty("getName");
|
||||
assertEquals(getName, "name");
|
||||
String setName = PropertyNamer.methodToProperty("setName");
|
||||
assertEquals(setName, "name");
|
||||
String isName = PropertyNamer.methodToProperty("isName");
|
||||
assertEquals(isName, "name");
|
||||
String name = PropertyNamer.methodToProperty("name");
|
||||
assertEquals(name, "name");
|
||||
name = PropertyNamer.methodToProperty("Name");
|
||||
assertEquals(name, "name");
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@ import com.zfoo.protocol.ProtocolManager;
|
||||
import com.zfoo.protocol.buffer.ByteBufUtils;
|
||||
import com.zfoo.protocol.generate.GenerateOperation;
|
||||
import com.zfoo.protocol.serializer.CodeLanguage;
|
||||
import com.zfoo.protocol.util.ClassUtils;
|
||||
import com.zfoo.protocol.util.FileUtils;
|
||||
import com.zfoo.protocol.util.JsonUtils;
|
||||
import com.zfoo.storage.anno.AliasFieldName;
|
||||
@@ -28,7 +27,8 @@ import com.zfoo.storage.manager.StorageInt;
|
||||
import com.zfoo.storage.manager.StorageManager;
|
||||
import com.zfoo.storage.util.ExportUtils;
|
||||
import com.zfoo.storage.util.LambdaUtils;
|
||||
import com.zfoo.storage.util.support.SerializableFunction;
|
||||
import com.zfoo.storage.util.PropertyNamer;
|
||||
import com.zfoo.storage.util.function.Func1;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.buffer.UnpooledHeapByteBuf;
|
||||
import org.junit.Ignore;
|
||||
@@ -96,7 +96,7 @@ public class ExportBinaryTesting {
|
||||
storageManager.initBefore();
|
||||
storageManager.initAfter();
|
||||
|
||||
// 生成协议 TODO 协议
|
||||
// 生成协议
|
||||
var protocols = new HashSet<Class<?>>();
|
||||
protocols.add(ResourceData.class);
|
||||
protocols.addAll(storageManager.storageMap().keySet());
|
||||
@@ -112,11 +112,13 @@ public class ExportBinaryTesting {
|
||||
var bytes = ByteBufUtils.readAllBytes(buffer);
|
||||
FileUtils.writeInputStreamToFile(new File("D:/github/godot-bird/binary_data.cfg"), new ByteArrayInputStream(bytes));
|
||||
|
||||
String methodName = LambdaUtils.extract(StudentResource::age).getImplMethodName();
|
||||
String fieldName = ClassUtils.getFieldName(methodName);
|
||||
Func1<StudentResource, Integer> ageFunc = StudentResource::age;
|
||||
String methodName = LambdaUtils.extract(ageFunc).getImplMethodName();
|
||||
String fieldName = PropertyNamer.methodToProperty(methodName);
|
||||
System.out.println(methodName);
|
||||
System.out.println(fieldName);
|
||||
|
||||
|
||||
//获取storage对象
|
||||
var storage = storageManager.getStorage(StudentResource.class);
|
||||
//获取唯一索引的对象
|
||||
|
||||
Reference in New Issue
Block a user