From 381e5b8d37237dbfb09c6a9d098dfa9d0e49e4b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=87=8C=E6=98=9F?= Date: Thu, 14 Sep 2023 18:38:08 +0800 Subject: [PATCH] =?UTF-8?q?perf[storage]:=E4=BC=98=E5=8C=96=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E8=A1=A8=E6=A8=A1=E5=9D=97=201.=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E5=BC=8F=E6=96=B9=E6=B3=95=E5=BC=95=E7=94=A8?= =?UTF-8?q?=E7=BC=93=E5=AD=98;=202.=E7=A7=BB=E9=99=A4guava=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E5=BA=93,=E5=87=8F=E5=B0=91=E7=AC=AC=E4=B8=89?= =?UTF-8?q?=E6=96=B9=E4=BE=9D=E8=B5=96;=203.=E4=BC=98=E5=8C=96=E9=83=A8?= =?UTF-8?q?=E5=88=86=E5=87=BD=E6=95=B0=E5=BC=8F=E6=8E=A5=E5=8F=A3;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/zfoo/protocol/util/ClassUtils.java | 32 +--- storage/pom.xml | 7 - .../java/com/zfoo/storage/StorageContext.java | 10 +- .../zfoo/storage/manager/StorageManager.java | 24 ++- .../zfoo/storage/manager/StorageObject.java | 74 ++------ .../java/com/zfoo/storage/model/IStorage.java | 6 +- .../com/zfoo/storage/util/LambdaUtils.java | 52 +++++- .../com/zfoo/storage/util/PropertyNamer.java | 43 +++++ .../com/zfoo/storage/util/SimpleCache.java | 172 ++++++++++++++++++ .../com/zfoo/storage/util/function/Func.java | 43 +++++ .../com/zfoo/storage/util/function/Func0.java | 39 ++++ .../com/zfoo/storage/util/function/Func1.java | 43 +++++ .../util/support/SerializableFunction.java | 13 -- .../zfoo/storage/TestLambdaFunctionCache.java | 20 ++ .../com/zfoo/storage/TestPropertyNamer.java | 28 +++ .../storage/export/ExportBinaryTesting.java | 12 +- 16 files changed, 495 insertions(+), 123 deletions(-) create mode 100644 storage/src/main/java/com/zfoo/storage/util/PropertyNamer.java create mode 100644 storage/src/main/java/com/zfoo/storage/util/SimpleCache.java create mode 100644 storage/src/main/java/com/zfoo/storage/util/function/Func.java create mode 100644 storage/src/main/java/com/zfoo/storage/util/function/Func0.java create mode 100644 storage/src/main/java/com/zfoo/storage/util/function/Func1.java delete mode 100644 storage/src/main/java/com/zfoo/storage/util/support/SerializableFunction.java create mode 100644 storage/src/test/java/com/zfoo/storage/TestLambdaFunctionCache.java create mode 100644 storage/src/test/java/com/zfoo/storage/TestPropertyNamer.java diff --git a/protocol/src/main/java/com/zfoo/protocol/util/ClassUtils.java b/protocol/src/main/java/com/zfoo/protocol/util/ClassUtils.java index e27b808e..908261cb 100644 --- a/protocol/src/main/java/com/zfoo/protocol/util/ClassUtils.java +++ b/protocol/src/main/java/com/zfoo/protocol/util/ClassUtils.java @@ -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); - } } diff --git a/storage/pom.xml b/storage/pom.xml index ab9ca1a8..24e9fcc8 100644 --- a/storage/pom.xml +++ b/storage/pom.xml @@ -31,7 +31,6 @@ 5.2.3 1.10.0 - 32.1.2-jre 17 UTF-8 @@ -112,12 +111,6 @@ ${junit.version} test - - - com.google.guava - guava - ${guava.version} - diff --git a/storage/src/main/java/com/zfoo/storage/StorageContext.java b/storage/src/main/java/com/zfoo/storage/StorageContext.java index 625d97dd..0855610f 100644 --- a/storage/src/main/java/com/zfoo/storage/StorageContext.java +++ b/storage/src/main/java/com/zfoo/storage/StorageContext.java @@ -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 List getIndexes(Class clazz, SerializableFunction function, K indexId) { - return instance.storageManager.getStorage(clazz).getIndexes(function, indexId); + public static List getIndexes(Class clazz, Func1 function, K keyId) { + return instance.storageManager.getStorage(clazz).getIndexes(function, keyId); } - public static V getUniqueIndex(Class clazz, SerializableFunction function, K indexId) { - return instance.storageManager.getStorage(clazz).getUniqueIndex(function, indexId); + public static V getUniqueIndex(Class clazz, Func1 func, K keyId) { + return instance.storageManager.getStorage(clazz).getUniqueIndex(func, keyId); } @Override diff --git a/storage/src/main/java/com/zfoo/storage/manager/StorageManager.java b/storage/src/main/java/com/zfoo/storage/manager/StorageManager.java index f97ea84c..dd510b07 100644 --- a/storage/src/main/java/com/zfoo/storage/manager/StorageManager.java +++ b/storage/src/main/java/com/zfoo/storage/manager/StorageManager.java @@ -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) storage.getAll(); } - public List getIndexes(Class clazz, SerializableFunction function, K indexId) { + public List getIndexes(Class clazz, Func1 func, K indexId) { var storage = getStorage(clazz); - return storage.getIndexes(function, indexId); + return storage.getIndexes(func, indexId); } - public T get(Class clazz, UQ uniqueId) { + public T get(Class clazz, UQ keyId) { IStorage storage = getStorage(clazz); - return storage.get(uniqueId); + return storage.get(keyId); } @Override diff --git a/storage/src/main/java/com/zfoo/storage/manager/StorageObject.java b/storage/src/main/java/com/zfoo/storage/manager/StorageObject.java index a145df16..b28b03e4 100644 --- a/storage/src/main/java/com/zfoo/storage/manager/StorageObject.java +++ b/storage/src/main/java/com/zfoo/storage/manager/StorageObject.java @@ -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 implements IStorage { - private ImmutableMap dataMap; + private Map dataMap = new HashMap<>(64); // 非唯一索引 - protected ImmutableMap>> indexMap; + protected Map>> indexMap = new HashMap<>(32); // 唯一索引 - protected ImmutableMap> uniqueIndexMap; + protected Map> uniqueIndexMap = new HashMap<>(16); protected Class clazz; protected IdDef idDef; - protected ImmutableMap indexDefMap; + protected Map indexDefMap; // 当前配置表是否在当前项目中使用,没有被使用的会清除data数据,以达到节省内存的目的 protected boolean recycle = true; @@ -59,9 +57,11 @@ public class StorageObject implements IStorage { 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 implements IStorage { } @Override - public List getIndexes(SerializableFunction indexFunction, K key) { - String indexName = ClassUtils.getFieldName(LambdaUtils.extract(indexFunction).getImplMethodName()); + public List getIndexes(Func1 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 implements IStorage { @Nullable @Override - public V getUniqueIndex(SerializableFunction uniqueIndexFunction, K key) { - String uniqueIndexName = ClassUtils.getFieldName(LambdaUtils.extract(uniqueIndexFunction).getImplMethodName()); + public V getUniqueIndex(Func1 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 implements IStorage { return dataMap.size(); } - private void append(List values) { - ImmutableMap.Builder dataMapBuilder = ImmutableMap.builder(); - Map> uniqueIndexMap = new HashMap<>(32); - Map>> 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()); list.add(v); } } return result; } - } diff --git a/storage/src/main/java/com/zfoo/storage/model/IStorage.java b/storage/src/main/java/com/zfoo/storage/model/IStorage.java index c7a6c28e..5ed18780 100644 --- a/storage/src/main/java/com/zfoo/storage/model/IStorage.java +++ b/storage/src/main/java/com/zfoo/storage/model/IStorage.java @@ -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 { IdDef getIdDef(); @Nullable - List getIndexes(SerializableFunction function, K key); + List getIndexes(Func1 function, K key); @Nullable - V getUniqueIndex(SerializableFunction function, K key); + V getUniqueIndex(Func1 function, K key); int size(); } diff --git a/storage/src/main/java/com/zfoo/storage/util/LambdaUtils.java b/storage/src/main/java/com/zfoo/storage/util/LambdaUtils.java index 8076da2b..c849213c 100644 --- a/storage/src/main/java/com/zfoo/storage/util/LambdaUtils.java +++ b/storage/src/main/java/com/zfoo/storage/util/LambdaUtils.java @@ -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 FUNC_CACHE = new SimpleCache<>(64); /** * 该缓存可能会在任意不定的时间被清除 @@ -27,7 +28,7 @@ public final class LambdaUtils { * @param 类型,被调用的 Function 对象的目标类型 * @return 返回解析后的结果 */ - public static LambdaMeta extract(SerializableFunction func) { + public static 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 setAccessible(T object) { return AccessController.doPrivileged(new SetAccessibleAction<>(object)); } + + /** + * 解析lambda表达式,加了缓存。 + * 该缓存可能会在任意不定的时间被清除 + * + * @param Lambda类型 + * @param func 需要解析的 lambda 对象(无参方法) + * @return 返回解析后的结果 + */ + public static LambdaMeta resolve(Func1 func) { + return _resolve(func); + } + + /** + * 获取lambda表达式函数(方法)名称 + * + * @param Lambda类型 + * @param func 函数(无参方法) + * @return 函数名称 + */ + public static String getMethodName(Func1 func) { + return resolve(func).getImplMethodName(); + } + + /** + * 获取lambda表达式函数(字段)名称 + * + * @param Lambda类型 + * @param func 函数 + * @return 字段名称 + */ + public static String getFieldName(Func1 func) { + return PropertyNamer.methodToProperty(getMethodName(func)); + } + + /** + * 解析lambda表达式,加了缓存。 + * 该缓存可能会在任意不定的时间被清除 + * + * @param func 需要解析的 lambda 对象 + * @return 返回解析后的结果 + */ + private static LambdaMeta _resolve(Serializable func) { + return FUNC_CACHE.get(func.getClass(), () -> extract(func)); + } } diff --git a/storage/src/main/java/com/zfoo/storage/util/PropertyNamer.java b/storage/src/main/java/com/zfoo/storage/util/PropertyNamer.java new file mode 100644 index 00000000..ccd9c02d --- /dev/null +++ b/storage/src/main/java/com/zfoo/storage/util/PropertyNamer.java @@ -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; + } + +} diff --git a/storage/src/main/java/com/zfoo/storage/util/SimpleCache.java b/storage/src/main/java/com/zfoo/storage/util/SimpleCache.java new file mode 100644 index 00000000..22351c49 --- /dev/null +++ b/storage/src/main/java/com/zfoo/storage/util/SimpleCache.java @@ -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 键类型 + * @param 值类型 + * @author Looly + */ +public class SimpleCache implements Iterable>, Serializable { + private static final long serialVersionUID = 1L; + + /** + * 池 + */ + private final Map cache; + // 乐观读写锁 + private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + /** + * 写的时候每个key一把锁,降低锁的粒度 + */ + protected final Map keyLockMap = new ConcurrentHashMap<>(); + + /** + * 构造,默认使用{@link WeakHashMap}实现缓存自动清理 + */ + public SimpleCache() { + this(32); + } + + public SimpleCache(int initialCapacity) { + this(new WeakHashMap<>(initialCapacity)); + } + + /** + * 构造 + *

+ * 通过自定义Map初始化,可以自定义缓存实现。
+ * 比如使用{@link WeakHashMap}则会自动清理key,使用HashMap则不会清理
+ * 同时,传入的Map对象也可以自带初始化的键值对,防止在get时创建 + *

+ * + * @param initMap 初始Map,用于定义Map类型 + */ + public SimpleCache(Map 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 supplier) { + return get(key, null, supplier); + } + + /** + * 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象 + * + * @param key 键 + * @param validPredicate 检查结果对象是否可用,如是否断开连接等 + * @param supplier 如果不存在回调方法或结果不可用,用于生产值对象 + * @return 值对象 + */ + public V get(K key, Predicate validPredicate, Func0 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> iterator() { + return this.cache.entrySet().iterator(); + } +} diff --git a/storage/src/main/java/com/zfoo/storage/util/function/Func.java b/storage/src/main/java/com/zfoo/storage/util/function/Func.java new file mode 100644 index 00000000..7a8af7be --- /dev/null +++ b/storage/src/main/java/com/zfoo/storage/util/function/Func.java @@ -0,0 +1,43 @@ +package com.zfoo.storage.util.function; + +import java.io.Serializable; + +/** + * 函数对象
+ * 接口灵感来自于ActFramework
+ * 一个函数接口代表一个一个函数,用于包装一个函数为对象
+ * 在JDK8之前,Java的函数并不能作为参数传递,也不能作为返回值存在,此接口用于将一个函数包装成为一个对象,从而传递对象 + * + * @author Looly + * + * @param

参数类型 + * @param 返回值类型 + * @since 3.1.0 + */ +@FunctionalInterface +public interface Func 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); + } + } +} diff --git a/storage/src/main/java/com/zfoo/storage/util/function/Func0.java b/storage/src/main/java/com/zfoo/storage/util/function/Func0.java new file mode 100644 index 00000000..dad2f4d9 --- /dev/null +++ b/storage/src/main/java/com/zfoo/storage/util/function/Func0.java @@ -0,0 +1,39 @@ +package com.zfoo.storage.util.function; + +import java.io.Serializable; + +/** + * 无参数的函数对象
+ * 接口灵感来自于ActFramework
+ * 一个函数接口代表一个一个函数,用于包装一个函数为对象
+ * 在JDK8之前,Java的函数并不能作为参数传递,也不能作为返回值存在,此接口用于将一个函数包装成为一个对象,从而传递对象 + * + * @author Looly + * + * @param 返回值类型 + * @since 4.5.2 + */ +@FunctionalInterface +public interface Func0 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); + } + } +} diff --git a/storage/src/main/java/com/zfoo/storage/util/function/Func1.java b/storage/src/main/java/com/zfoo/storage/util/function/Func1.java new file mode 100644 index 00000000..bd38f112 --- /dev/null +++ b/storage/src/main/java/com/zfoo/storage/util/function/Func1.java @@ -0,0 +1,43 @@ +package com.zfoo.storage.util.function; + +import java.io.Serializable; + +/** + * 只有一个参数的函数对象
+ * 接口灵感来自于ActFramework
+ * 一个函数接口代表一个一个函数,用于包装一个函数为对象
+ * 在JDK8之前,Java的函数并不能作为参数传递,也不能作为返回值存在,此接口用于将一个函数包装成为一个对象,从而传递对象 + * + * @author Looly + * + * @param

参数类型 + * @param 返回值类型 + * @since 4.2.2 + */ +@FunctionalInterface +public interface Func1 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); + } + } +} diff --git a/storage/src/main/java/com/zfoo/storage/util/support/SerializableFunction.java b/storage/src/main/java/com/zfoo/storage/util/support/SerializableFunction.java deleted file mode 100644 index eac5f769..00000000 --- a/storage/src/main/java/com/zfoo/storage/util/support/SerializableFunction.java +++ /dev/null @@ -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 extends Function, Serializable { -} diff --git a/storage/src/test/java/com/zfoo/storage/TestLambdaFunctionCache.java b/storage/src/test/java/com/zfoo/storage/TestLambdaFunctionCache.java new file mode 100644 index 00000000..5bbd9e36 --- /dev/null +++ b/storage/src/test/java/com/zfoo/storage/TestLambdaFunctionCache.java @@ -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 nameFunc = StudentResource::getName; + System.out.println(LambdaUtils.getMethodName(nameFunc)); + System.out.println(LambdaUtils.getMethodName(nameFunc)); + } +} diff --git a/storage/src/test/java/com/zfoo/storage/TestPropertyNamer.java b/storage/src/test/java/com/zfoo/storage/TestPropertyNamer.java new file mode 100644 index 00000000..5ff48294 --- /dev/null +++ b/storage/src/test/java/com/zfoo/storage/TestPropertyNamer.java @@ -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"); + } +} diff --git a/storage/src/test/java/com/zfoo/storage/export/ExportBinaryTesting.java b/storage/src/test/java/com/zfoo/storage/export/ExportBinaryTesting.java index e5e197f3..0f541916 100644 --- a/storage/src/test/java/com/zfoo/storage/export/ExportBinaryTesting.java +++ b/storage/src/test/java/com/zfoo/storage/export/ExportBinaryTesting.java @@ -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>(); 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 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); //获取唯一索引的对象