簡體   English   中英

ByteBuddy:在構造類期間在攔截中使用新定義的字段

[英]ByteBuddy: Use new defined field in intercept during construction of class

我正在看別人的一些ByteBuddy代碼。 他使用ByteBuddy生成運行時子類,這些子類用作代理以將其運行時的一些管理代碼實現為特定對象。

Class<? extends T> newSubClass = new ByteBuddy(ClassFileVersion.ofThisVm())
                .subclass(classType)
                .defineField("_core", Object.class, Visibility.PUBLIC) //<---
                .method(ElementMatchers.isDeclaredBy(classType))
                .intercept(InvocationHandlerAdapter.of((proxy, method, m_args) -> {
                    //TODO: Need to replace core with _core as core is a function argument and will make it bound
                    return proxyHandler(core, method, m_args); //<--
                }))
                .make()
                .load(roleType.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                .getLoaded();


T proxy = ReflectionHelper.newInstance(newSubClass, args);
newSubClass.getField("_core").set(proxy, core);

為了不將core對象直接綁定到lambda中,我想使用新定義的字段_core以便我可以重用生成的類(而不是在每次調用函數時重新生成它)。 有沒有辦法做到這一點?

提前致謝。

您可以像定義方法一樣定義自定義構造函數。 定義構造函數的一個重要點是,您需要另一個構造函數調用作為其第一條指令。 您可以使用MethodCall::invoke調用構造函數,該方法可以與FieldAccessor::ofField結合使用。

這樣,您可以類似於以下內容來定義您的類:

new ByteBuddy(ClassFileVersion.ofThisVm())
  .subclass(classType, ConstructorStrategy.Default.NO_CONSTRUCTORS)
  .defineConstructor(Visibility.PUBLIC)
    .withParameter(InvocationHandler.class)
    .intercept(MethodCall.invoke(classType.getDeclaredConstructor())
    .andThen(FieldAccessor.ofField("_core").setsArgumentAt(0)))
  .defineField("_core", InvocationHandler.class, Visibility.PUBLIC)
  .method(ElementMatchers.isDeclaredBy(classType))
    .intercept(InvocationHandlerAdapter.toField("_core"))
  .make();

這樣,您可以為每個實例設置自定義InvocationHandler 如果您只想將狀態存儲在_core字段中,並從攔截器訪問此字段,請查看MethodDelegation

new ByteBuddy(ClassFileVersion.ofThisVm())
  .subclass(classType, ConstructorStrategy.Default.NO_CONSTRUCTORS)
  .defineConstructor(Visibility.PUBLIC)
    .withParameter(Object.class)
    .intercept(MethodCall.invoke(classType.getDeclaredConstructor())
    .andThen(FieldAccessor.ofField("_core").setsArgumentAt(0)))
  .defineField("_core", Object.class, Visibility.PUBLIC)
  .method(ElementMatchers.isDeclaredBy(classType))
    .intercept(MethodDelegation.to(MyHandler.class))
  .make();

public class MyHandler {
  @RuntimeType
  public static Object intercept(@FieldValue("_core") Object value) { ... }
}

您可能需要的其他注釋是@This@AllArguments@Origin@SuperCall 您需要的越少,代理的效率就越高。 特別是@AllArguments由於其分配要求而非常昂貴。

請注意,在這種情況下,僅在超級構造函數調用之后設置您的字段。 此外,您假定超級類型中包含默認構造函數。 另外,您可以實現自定義的ConstructorStrategy

至於緩存,請看一下Byte Buddy的TypeCache

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM