perf[storage]:优化配置表模块

1.增加函数式方法引用缓存;
2.移除guava依赖库,减少第三方依赖;
3.优化部分函数式接口;
This commit is contained in:
凌星
2023-09-14 18:38:08 +08:00
parent f338bf41a8
commit 381e5b8d37
16 changed files with 495 additions and 123 deletions
@@ -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);
}
}
-7
View File
@@ -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);
//获取唯一索引的对象