有一堂课。
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
来做到这一点?
答案 0 :(得分:1)
以您似乎想要的方式显式使用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
解决方案才可以接受,但是每次调用都如此频繁,以至于Method#invoke
的开销太高了。
因此,我继续进行了一些快速基准测试。在您的用例中,您在程序启动时初始化MapHandler
,然后仅调用它们,我的技术和您的技术大致相同。它们都太快了,以至于我实际上无法测量调用各种MapHandler
所花费的时间差异。通常,LambdaMetafactory
更为糟糕,因为创建匿名类会花费很多时间。实际上,您制作的课程越多,花费的时间就越长。同时,method.invoke
lambda只需构造一个对象,通常速度快数千倍。