perf[storage]: Interface optimization

1.优化storage函数式方法引用缓存,采用spring自带的实现;
2.优化合并属性工具类;
This commit is contained in:
凌星
2023-09-15 16:51:14 +08:00
parent 93ce3187c4
commit f2ff1fd237
12 changed files with 181 additions and 298 deletions
@@ -457,8 +457,8 @@ public class OrmManager implements IOrmManager {
for (var field : filedList) {
// entity必须包含属性的get和set方法
ReflectionUtils.fieldToGetMethod(clazz, field);
ReflectionUtils.fieldToSetMethod(clazz, field);
FieldUtils.fieldToGetMethod(clazz, field);
FieldUtils.fieldToSetMethod(clazz, field);
// 是一个基本类型变量
var fieldType = field.getType();
@@ -21,7 +21,7 @@ import com.zfoo.protocol.generate.GenerateProtocolFile;
import com.zfoo.protocol.registration.field.IFieldRegistration;
import com.zfoo.protocol.serializer.enhance.*;
import com.zfoo.protocol.serializer.reflect.*;
import com.zfoo.protocol.util.ReflectionUtils;
import com.zfoo.protocol.util.FieldUtils;
import com.zfoo.protocol.util.StringUtils;
import io.netty.buffer.ByteBuf;
import javassist.*;
@@ -198,7 +198,7 @@ public abstract class EnhanceUtils {
.writeObject(builder, StringUtils.format("packet.{}", field.getName()), field, fieldRegistration);
} else {
enhanceSerializer(fieldRegistration.serializer())
.writeObject(builder, StringUtils.format("packet.{}()", ReflectionUtils.fieldToGetMethod(packetClazz, field)), field, fieldRegistration);
.writeObject(builder, StringUtils.format("packet.{}()", FieldUtils.fieldToGetMethod(packetClazz, field)), field, fieldRegistration);
}
}
builder.append("}");
@@ -246,7 +246,7 @@ public abstract class EnhanceUtils {
if (Modifier.isPublic(field.getModifiers())) {
builder.append(StringUtils.format("packet.{}={};", field.getName(), readObject));
} else {
builder.append(StringUtils.format("packet.{}({});", ReflectionUtils.fieldToSetMethod(packetClazz, field), readObject));
builder.append(StringUtils.format("packet.{}({});", FieldUtils.fieldToSetMethod(packetClazz, field), readObject));
}
}
}
@@ -0,0 +1,101 @@
package com.zfoo.protocol.util;
import com.zfoo.protocol.exception.RunException;
import java.lang.reflect.Field;
import java.util.Locale;
/**
* 属性工具类
*
* @author veione
*/
public class FieldUtils {
public static String fieldToGetMethod(Class<?> clazz, Field field) {
var fieldName = field.getName();
ReflectionUtils.assertIsStandardFieldName(field);
var methodName = "get" + StringUtils.capitalize(fieldName);
if (clazz.isRecord()) {
methodName = fieldName;
}
try {
clazz.getDeclaredMethod(methodName);
return methodName;
} catch (NoSuchMethodException e) {
// java的get方法对boolean值有可能对应get或者is,所以尝试获取两种不同的get方法,当两种都获取不到才抛异常
}
// 如果属性名的第一个字母是小写且第二个字母大写,那么该属性名直接用作 getter/setter。例如属性名为uName,对应的方法是getuName/setuName。
// 如果属性名以大写字母开头,属性名直接用作 getter/setter 方法中 get/set 的后部分。例如属性名为Name,对应的方法是getName/setName。
methodName = "get" + fieldName;
try {
clazz.getDeclaredMethod(methodName);
return methodName;
} catch (NoSuchMethodException e) {
}
methodName = "is" + StringUtils.capitalize(fieldName);
try {
clazz.getDeclaredMethod(methodName);
return methodName;
} catch (NoSuchMethodException e) {
throw new RunException("field:[{}] has no getMethod or isMethod in class:[{}]", field.getName(), clazz.getCanonicalName());
}
}
public static String fieldToSetMethod(Class<?> clazz, Field field) {
var fieldName = field.getName();
ReflectionUtils.assertIsStandardFieldName(field);
var methodName = "set" + StringUtils.capitalize(fieldName);
if (clazz.isRecord()) {
return methodName;
}
try {
clazz.getDeclaredMethod(methodName, field.getType());
return methodName;
} catch (NoSuchMethodException e) {
}
methodName = "set" + fieldName;
try {
clazz.getDeclaredMethod(methodName, field.getType());
return methodName;
} catch (NoSuchMethodException e) {
throw new RunException("field:[{}] has no setMethod in class:[{}]", field.getName(), clazz.getCanonicalName());
}
}
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;
}
}
@@ -320,67 +320,6 @@ public abstract class ReflectionUtils {
.toList();
}
public static String fieldToGetMethod(Class<?> clazz, Field field) {
var fieldName = field.getName();
assertIsStandardFieldName(field);
var methodName = "get" + StringUtils.capitalize(fieldName);
if (clazz.isRecord()) {
methodName = fieldName;
}
try {
clazz.getDeclaredMethod(methodName);
return methodName;
} catch (NoSuchMethodException e) {
// java的get方法对boolean值有可能对应get或者is,所以尝试获取两种不同的get方法,当两种都获取不到才抛异常
}
// 如果属性名的第一个字母是小写且第二个字母大写,那么该属性名直接用作 getter/setter。例如属性名为uName,对应的方法是getuName/setuName。
// 如果属性名以大写字母开头,属性名直接用作 getter/setter 方法中 get/set 的后部分。例如属性名为Name,对应的方法是getName/setName。
methodName = "get" + fieldName;
try {
clazz.getDeclaredMethod(methodName);
return methodName;
} catch (NoSuchMethodException e) {
}
methodName = "is" + StringUtils.capitalize(fieldName);
try {
clazz.getDeclaredMethod(methodName);
return methodName;
} catch (NoSuchMethodException e) {
throw new RunException("field:[{}] has no getMethod or isMethod in class:[{}]", field.getName(), clazz.getCanonicalName());
}
}
public static String fieldToSetMethod(Class<?> clazz, Field field) {
var fieldName = field.getName();
assertIsStandardFieldName(field);
var methodName = "set" + StringUtils.capitalize(fieldName);
if (clazz.isRecord()) {
return methodName;
}
try {
clazz.getDeclaredMethod(methodName, field.getType());
return methodName;
} catch (NoSuchMethodException e) {
}
methodName = "set" + fieldName;
try {
clazz.getDeclaredMethod(methodName, field.getType());
return methodName;
} catch (NoSuchMethodException e) {
throw new RunException("field:[{}] has no setMethod in class:[{}]", field.getName(), clazz.getCanonicalName());
}
}
public static <T> Constructor<T> getConstructor(Class<T> clazz) {
try {
return clazz.getDeclaredConstructor();
@@ -17,6 +17,7 @@ import com.zfoo.protocol.collection.CollectionUtils;
import com.zfoo.protocol.exception.ExceptionUtils;
import com.zfoo.protocol.exception.RunException;
import com.zfoo.protocol.util.ClassUtils;
import com.zfoo.protocol.util.FieldUtils;
import com.zfoo.protocol.util.FileUtils;
import com.zfoo.protocol.util.GraalVmUtils;
import com.zfoo.protocol.util.ReflectionUtils;
@@ -123,7 +124,7 @@ public class StorageManager implements IStorageManager {
var setMethodName = StringUtils.EMPTY;
try {
setMethodName = ReflectionUtils.fieldToSetMethod(clazz, field);
setMethodName = FieldUtils.fieldToSetMethod(clazz, field);
} catch (Exception e) {
// 没有setMethod是正确的
}
@@ -1,5 +1,6 @@
package com.zfoo.storage.util;
import com.zfoo.protocol.util.FieldUtils;
import com.zfoo.protocol.util.ReflectionUtils;
import com.zfoo.storage.util.function.Func1;
import com.zfoo.storage.util.support.IdeaProxyLambdaMeta;
@@ -7,6 +8,7 @@ import com.zfoo.storage.util.support.LambdaMeta;
import com.zfoo.storage.util.support.ReflectLambdaMeta;
import com.zfoo.storage.util.support.SerializedLambda;
import com.zfoo.storage.util.support.ShadowLambdaMeta;
import org.springframework.util.ConcurrentReferenceHashMap;
import java.io.Serializable;
import java.lang.reflect.Method;
@@ -15,19 +17,17 @@ import java.lang.reflect.Proxy;
/**
* @author veione
* @version 1.0
* @date 2023/9/12
*/
public final class LambdaUtils {
private static final SimpleCache<Class, LambdaMeta> FUNC_CACHE = new SimpleCache<>(64);
private static final ConcurrentReferenceHashMap<Class, LambdaMeta> CACHE = new ConcurrentReferenceHashMap<>(64, 0.75F, 16, ConcurrentReferenceHashMap.ReferenceType.WEAK);
/**
* 该缓存可能会在任意不定的时间被清除
*
* @param func 需要解析的 lambda 对象
* @param <T> 类型,被调用的 Function 对象的目标类型
* @return 返回解析后的结果
*/
public static <T> LambdaMeta extract(Serializable func) {
public static LambdaMeta extract(Serializable func) {
// 1. IDEA 调试模式下 lambda 表达式是一个代理
if (func instanceof Proxy) {
return new IdeaProxyLambdaMeta((Proxy) func);
@@ -75,7 +75,7 @@ public final class LambdaUtils {
* @return 字段名称
*/
public static <T> String getFieldName(Func1<T, ?> func) {
return PropertyNamer.methodToProperty(getMethodName(func));
return FieldUtils.methodToProperty(getMethodName(func));
}
/**
@@ -85,7 +85,7 @@ public final class LambdaUtils {
* @param func 需要解析的 lambda 对象
* @return 返回解析后的结果
*/
private static <T> LambdaMeta _resolve(Serializable func) {
return FUNC_CACHE.get(func.getClass(), () -> extract(func));
private static LambdaMeta _resolve(Serializable func) {
return CACHE.computeIfAbsent(func.getClass(), c -> extract(func));
}
}
@@ -1,43 +0,0 @@
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;
}
}
@@ -1,172 +0,0 @@
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();
}
}
@@ -19,6 +19,21 @@
"lambdaCapturingTypes": [
{
"name": "com.zfoo.storage.util.LambdaUtils"
},
{
"name": "com.zfoo.storage.util.support.SerializedLambda"
},
{
"name": "java.lang.invoke.SerializedLambda"
},
{
"name": "com.zfoo.storage.util.function.Func"
},
{
"name": "com.zfoo.storage.util.function.Func0"
},
{
"name": "com.zfoo.storage.util.function.Func1"
}
]
}
@@ -1,6 +1,6 @@
package com.zfoo.storage;
import com.zfoo.storage.util.PropertyNamer;
import com.zfoo.protocol.util.FieldUtils;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@@ -9,20 +9,20 @@ import static org.junit.Assert.assertEquals;
* @author veione
* @version 1.0.0
*/
public class TestPropertyNamer {
public class TestFieldUtils {
@Test
public void testPropertyName() {
//前三种主要用于普通的POJO,第四种用于是record类型,方法名就是属性名
String getName = PropertyNamer.methodToProperty("getName");
String getName = FieldUtils.methodToProperty("getName");
assertEquals(getName, "name");
String setName = PropertyNamer.methodToProperty("setName");
String setName = FieldUtils.methodToProperty("setName");
assertEquals(setName, "name");
String isName = PropertyNamer.methodToProperty("isName");
String isName = FieldUtils.methodToProperty("isName");
assertEquals(isName, "name");
String name = PropertyNamer.methodToProperty("name");
String name = FieldUtils.methodToProperty("name");
assertEquals(name, "name");
name = PropertyNamer.methodToProperty("Name");
name = FieldUtils.methodToProperty("Name");
assertEquals(name, "name");
}
}
@@ -0,0 +1,42 @@
package com.zfoo.storage;
import com.zfoo.storage.util.LambdaUtils;
import com.zfoo.storage.util.function.Func1;
import com.zfoo.storage.util.support.LambdaMeta;
import org.junit.Test;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.function.Function;
/**
* @author veione
* @version 1.0.0
*/
public class TestLambdaFunction {
//https://blog.csdn.net/iteye_19045/article/details/119299015
@Test
public void testFuncSerialization() throws Exception {
Func1<StudentResource, String> func = StudentResource::name;
Object object = getObject(func);
System.out.println(object);
Class<? extends Serializable> clazz = func.getClass();
Method writeReplace = clazz.getDeclaredMethod("writeReplace");
System.out.println(writeReplace);
LambdaMeta meta = LambdaUtils.extract(func);
System.out.println(meta);
Function<StudentResource, String> func2 = StudentResource::name;
Method method = func2.getClass().getDeclaredMethod("writeReplace");
object = method.invoke(func2);
System.out.println(object);
}
private static Object getObject(Serializable func) throws Exception {
Method method = func.getClass().getDeclaredMethod("writeReplace");
Object object = method.invoke(func);
return object;
}
}
@@ -16,6 +16,7 @@ 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.FieldUtils;
import com.zfoo.protocol.util.FileUtils;
import com.zfoo.protocol.util.JsonUtils;
import com.zfoo.storage.anno.AliasFieldName;
@@ -27,7 +28,6 @@ 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.PropertyNamer;
import com.zfoo.storage.util.function.Func1;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.UnpooledHeapByteBuf;
@@ -114,7 +114,7 @@ public class ExportBinaryTesting {
Func1<StudentResource, Integer> ageFunc = StudentResource::age;
String methodName = LambdaUtils.extract(ageFunc).getImplMethodName();
String fieldName = PropertyNamer.methodToProperty(methodName);
String fieldName = FieldUtils.methodToProperty(methodName);
System.out.println(methodName);
System.out.println(fieldName);