有一个班。

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);
})

可以通过MethodHandleLambdaMetaFactory做到吗?

最佳答案

以您似乎想要的方式显式使用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类,该类将methodbean作为实例变量。在第一次执行引导invokedynamic的代码之后,只需实例化此匿名类即可创建每个MapHandler。仅当您只需要相对较少的LambdaMetafactory时,我的MapHandler解决方案才似乎可以接受,但是每个odt_code的调用频率很高,因此Method#invoke的开销太高。

因此,我继续进行了一些快速基准测试。在您的用例中,在程序启动时初始化MapHandler,然后仅调用它们,我的技术和您的技术大致相同。它们都太快了,以至于我实际上无法测量调用不同类型的MapHandler所花费的时间差异。通常,LambdaMetafactory会更糟,因为创建匿名类会花费很多时间。实际上,您制作的 class 越多,花费的时间就越长。同时,method.invoke lambda只需构造一个对象,通常速度快数千倍。

10-06 13:40