mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2026-05-29 18:57:11 +08:00
!1433 perf(core): 为ReflectUtil.getMethod新增细粒度方法查找缓存,提升高频反射调用性能
Merge pull request !1433 from 07heco/perf/reflectutil-method-cache
This commit is contained in:
@@ -36,6 +36,12 @@ public class ReflectUtil {
|
||||
* 方法缓存
|
||||
*/
|
||||
private static final WeakKeyValueConcurrentMap<Class<?>, Method[]> METHODS_CACHE = new WeakKeyValueConcurrentMap<>();
|
||||
/**
|
||||
* 方法查找结果缓存(新增:细粒度缓存,避免重复遍历)
|
||||
* key: 方法查找键(类+是否忽略大小写+方法名+参数类型)
|
||||
* value: 查找到的Method
|
||||
*/
|
||||
private static final WeakKeyValueConcurrentMap<MethodLookupKey, Method> METHOD_LOOKUP_CACHE = new WeakKeyValueConcurrentMap<>();
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------- Constructor
|
||||
|
||||
@@ -534,21 +540,25 @@ public class ReflectUtil {
|
||||
if (null == clazz || StrUtil.isBlank(methodName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Method res = null;
|
||||
final Method[] methods = getMethods(clazz);
|
||||
if (ArrayUtil.isNotEmpty(methods)) {
|
||||
for (Method method : methods) {
|
||||
if (StrUtil.equals(methodName, method.getName(), ignoreCase)
|
||||
&& ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes)
|
||||
//排除协变桥接方法,pr#1965@Github
|
||||
&& (res == null
|
||||
|| res.getReturnType().isAssignableFrom(method.getReturnType()))) {
|
||||
res = method;
|
||||
// 优先从细粒度缓存查找
|
||||
final MethodLookupKey key = new MethodLookupKey(clazz, ignoreCase, methodName, paramTypes);
|
||||
return METHOD_LOOKUP_CACHE.computeIfAbsent(key, (lookupKey) -> {
|
||||
// 缓存未命中时,执行原有的查找逻辑
|
||||
Method res = null;
|
||||
final Method[] methods = getMethods(clazz);
|
||||
if (ArrayUtil.isNotEmpty(methods)) {
|
||||
for (Method method : methods) {
|
||||
if (StrUtil.equals(methodName, method.getName(), ignoreCase)
|
||||
&& ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes)
|
||||
//排除协变桥接方法,pr#1965@Github
|
||||
&& (res == null
|
||||
|| res.getReturnType().isAssignableFrom(method.getReturnType()))) {
|
||||
res = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1193,4 +1203,40 @@ public class ReflectUtil {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 方法查找键(用于细粒度缓存)
|
||||
* 用于唯一标识一次方法查找操作
|
||||
*/
|
||||
private static class MethodLookupKey {
|
||||
private final Class<?> clazz;
|
||||
private final boolean ignoreCase;
|
||||
private final String methodName;
|
||||
private final Class<?>[] paramTypes;
|
||||
|
||||
public MethodLookupKey(Class<?> clazz, boolean ignoreCase, String methodName, Class<?>[] paramTypes) {
|
||||
this.clazz = clazz;
|
||||
this.ignoreCase = ignoreCase;
|
||||
this.methodName = methodName;
|
||||
this.paramTypes = paramTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
MethodLookupKey that = (MethodLookupKey) o;
|
||||
return ignoreCase == that.ignoreCase &&
|
||||
Objects.equals(clazz, that.clazz) &&
|
||||
Objects.equals(methodName, that.methodName) &&
|
||||
Arrays.equals(paramTypes, that.paramTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Objects.hash(clazz, ignoreCase, methodName);
|
||||
result = 31 * result + Arrays.hashCode(paramTypes);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,4 +412,29 @@ public class ReflectUtilTest {
|
||||
assertInstanceOf(LinkedList.class, dequeInstance);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证getMethod缓存功能正常,结果与原逻辑一致
|
||||
*/
|
||||
@Test
|
||||
public void testGetMethodWithCache() {
|
||||
// 1. 正常方法查找验证
|
||||
Method method1 = ReflectUtil.getMethod(String.class, "substring", int.class, int.class);
|
||||
assertNotNull(method1);
|
||||
assertEquals("substring", method1.getName());
|
||||
|
||||
// 2. 验证缓存命中:多次调用返回同一个对象
|
||||
Method method2 = ReflectUtil.getMethod(String.class, "substring", int.class, int.class);
|
||||
assertSame(method1, method2);
|
||||
|
||||
// 3. 忽略大小写场景验证
|
||||
Method methodIgnoreCase1 = ReflectUtil.getMethodIgnoreCase(String.class, "SUBSTRING", int.class, int.class);
|
||||
assertNotNull(methodIgnoreCase1);
|
||||
Method methodIgnoreCase2 = ReflectUtil.getMethodIgnoreCase(String.class, "substring", int.class, int.class);
|
||||
assertSame(methodIgnoreCase1, methodIgnoreCase2);
|
||||
|
||||
// 4. 边界场景:不存在的方法返回null
|
||||
Method nullMethod = ReflectUtil.getMethod(String.class, "notExistMethod", String.class);
|
||||
assertNull(nullMethod);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user