有一个班。
class A {
Mono<Response> testMap(Mono<Request> reqMono)
}
有功能界面
interface MapHandler {
Mono<?> handle(Mono<?> reqMono)
}
现在我可以写这个
{
A a = new A();
MapHandler handler = a::testMap;
}
我想构建一个工具,该工具可以检测Bean(对象)中的MapHandler的和所有并收集它们。
我已经试过了
List<MapHandler> list = initedList;
Method method = bean.getClass().getDeclaredMethods()[0];
list.put("methodName", req -> {
return (Mono<?>) method.invoke(bean, req);
})
可以通过
MethodHandle
或LambdaMetaFactory
做到吗? 最佳答案
以您似乎想要的方式显式使用LambdaMetafactory
的解决方案的粗略草图是:
// the signature of the method returned by LambdaMetaFactory
// it takes an object of bean's type and makes a MapHandler that calls one
// of its instance methods
MethodType mkLambdaType = MethodType.methodType(MapHandler.class, bean.getClass());
// the signature of the method in MapHandler being implemented
MethodType handleType = MethodType.methodType(Mono.class, Mono.class);
MethodHandles.Lookup lookup = MethodHandles.lookup();
// FYI this won't search in supertypes
// getMethods() will, but you only get public ones even if you have more privileged access
// you decide what to do here; the loop body is the important thing
for(Method method : bean.getClass().getDeclaredMethods()) {
if(Modifier.isStatic(method.getModifiers())) continue;
try {
MethodHandle target = lookup.unreflect(method);
CallSite mkLambda = LambdaMetafactory.metafactory
(lookup, "handle", mkLambdaType, handleType, target, handleType);
list.add((MapHandler)mkLambda.getTarget().invoke(bean));
} catch(IllegalAccessException | LambdaConversionException e) {
// because I am lazy, I'm not checking that method has the correct type
// I'm letting LambdaMetafactory throw if that's not the case
// if you choose not to use LambdaMetafactory, you may have to implement
// this type-checking
continue;
} catch(Throwable t) {
// Throwables come from the MethodHandle#invoke call
// but nothing should be thrown at all, because LambdaMetafactory
// produces its errors from metafactory, early, which are caught above
throw new RuntimeException("Unexpected error during reflection", t);
}
}
我相信这是非常浪费的。
LambdaMetafactory
的常见实现可能会在metafactory
调用中创建一个全新的类,返回指向构造函数或类似构造函数的CallSite
。这意味着您获得的每个MapHandler
是在运行时创建的其自己的匿名类。相反,您最初使用lambda调用Method
的想法比JVM好得多。 lambda导致创建单个LambdaMetafactory
类,该类将method
和bean
作为实例变量。在第一次执行引导invokedynamic
的代码之后,只需实例化此匿名类即可创建每个MapHandler
。仅当您只需要相对较少的LambdaMetafactory
时,我的MapHandler
解决方案才似乎可以接受,但是每个odt_code的调用频率很高,因此Method#invoke
的开销太高。因此,我继续进行了一些快速基准测试。在您的用例中,在程序启动时初始化
MapHandler
,然后仅调用它们,我的技术和您的技术大致相同。它们都太快了,以至于我实际上无法测量调用不同类型的MapHandler
所花费的时间差异。通常,LambdaMetafactory
会更糟,因为创建匿名类会花费很多时间。实际上,您制作的 class 越多,花费的时间就越长。同时,method.invoke
lambda只需构造一个对象,通常速度快数千倍。