クラスがあります。
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
あなたが得るには、実行時に作成した、独自の匿名クラスです。これとは対照的に、呼び出すためにラムダを使ってあなたのオリジナルのアイデアは、Method
JVMに非常に良くあります。ラムダは、単一の作成原因とLambdaMetafactory
保持し、クラス、method
およびbean
インスタンス変数としてを。コードを通じて、最初の実行後にinvokedynamic
ブートストラップされ、それぞれがMapHandler
この匿名クラスをインスタンス化するだけで作成されます。私のLambdaMetafactory
ソリューションは、あなただけの比較的少数の必要がある場合は、許容できると思われるMapHandler
のが、しかしそれぞれがそれほど頻繁に呼び出されるのオーバーヘッドMethod#invoke
高すぎます。
だから私は先に行ってといくつかの簡単なベンチマークを行ってきました。あなたが初期化するご利用の場合、MapHandler
プログラム開始時にSをしてからちょうどそれらを起動し、私の技術とあなたはほぼ同じです。彼らは両方とも非常に速く、私は実際にはさまざまな種類のを起動するのにかかる時間に差を測定することができないということですMapHandler
。一般的には、LambdaMetafactory
匿名クラスを作成するには時間がかかるので、悪いことです。実際には、あなたが作るより多くのクラスが、もはやそれがかかります。一方、method.invoke
ラムダは、単に数千倍速いことが多いです一つのオブジェクトを構築する必要があります。