gpt4 book ai didi

Java 字节码 : Customized setter/getter with byte buddy

转载 作者:搜寻专家 更新时间:2023-11-01 03:04:43 24 4
gpt4 key购买 nike

我正在尝试为带有字节伙伴的字段创建一个“自定义”setter 方法。Buddy 自己的机制允许非常容易地实现标准的 setter/getter 方法,但是,我正在寻找一种优雅的方式来使用一些额外的逻辑来扩展 setter。

为简化示例,假设我们有一个类 A,它有一个方法 setChanged(String)。目标是做一个A的子类,添加一个字段对应的访问方法。问题是,我想从每个添加的 setter 方法中调用 setChanged("fieldName")。

public void setName(String name)
{
setChanged("name");
this.name = name;
}

对于“普通”setter 方法,byte byddy 实现将是:

new ByteBuddy()
.subclass(A.class)
.name("B")
.defineField("name", Integer.TYPE, Visibility.PUBLIC)
// args is a ArrayList<Class<?>>
.defineMethod(getSetterName(name), Void.TYPE, args, Visibility.PUBLIC)
.intercept( FieldAccessor.ofField(name) )

我想要的字节码是这样的:

L0
ALOAD 0 // Loads the this reference onto the operand stack
ILOAD 1 // Loads the integer value of the local variable 1 (first method arg)
PUTFIELD package/B.name : I // stores the value to the field
L1
ALOAD 0
LDC "name"
INVOKEVIRTUAL package/A.setChanged (Ljava/lang/String;)V
RETURN

我的问题是:有没有办法在这种情况下重用 FieldAccessor?

最佳答案

从今天开始,您需要定义一个自定义的 Instrumentation 来完成这样的自定义工作。正如评论中所指出的,您随后可以使用 Instrumentation.Compound 将新行为添加到例如 FieldAccessor.ofBeanProperty() 之前,从而重用字段访问器代码。

为了添加自定义代码,字节好友了解不同的抽象级别:

  1. Instrumentation:定义方法的实现方式。仪器能够定义实现方法所需的附加字段、方法或静态初始化程序 block 。此外,它确定是否要为类型定义方法。
  2. ByteCodeAppenderInstrumentation 发出,并确定定义的方法是否是抽象的,如果方法已实现,则确定方法的字节码。
  3. StackManipulation 是一个字节码指令,对操作数栈的大小有一定的影响。堆栈操作用于实现非抽象方法。

为了在字节码中调用方法,您需要将所有参数(包括this)加载到堆栈上,并在放置所有这些参数后调用该方法。这可以按如下方式完成:

  1. 通过 MethodVariableAccess.REFERENCE.loadFromIndex(0)this 引用加载到堆栈上。
  2. 将描述正在访问的字段的字符串加载到堆栈上。这可以从作为参数提供给 ByteCodeAppender 的方法名称派生。使用 TextConstant,然后可以将名称放在堆栈上。
  3. 然后可以使用 MethodInvocation 调用方法,其中 setChanged 方法可以从创建的检测类型中提取>TypeDescription 作为参数提供给 Instrumentation

当然,这不是很漂亮,Byte Buddy 的愿望是向用户隐藏这个字节代码级别的 API,并用 DSL 或纯 Java 表达任何内容。因此,您可能会很高兴听到我目前正在使用 Byte Buddy 0.4 版,它具有一些您可以用于此目的的功能。对于您的示例,您可以使用 Byte Buddy 瑞士军刀的扩展形式 MethodDelegation 来实现自定义 setter 。方法委托(delegate)允许您通过使用注释委托(delegate)对任何 Java 方法的调用来实现方法。

假设您的 bean 实现了一个类型:

interface Changeable {
void setChanged(String field);
}

您可以使用以下方法拦截方法调用:

class Interceptor {
static void intercept(@This Changeable thiz, @Origin Method method) {
thiz.setChanged(method.getName());
}
}

使用方法委托(delegate),字节好友将始终在调用方法时调用拦截器。向拦截器方法传递描述特定拦截上下文的参数。上面,传递了this引用和被拦截的方法。

当然我们还缺少字段的实际设置。但是,使用 Byte Buddy 0.4,您现在可以创建一个新的 Instrumentation,如下所示:

MethodDelegation.to(Interceptor.class).andThen(FieldAccessor.ofBeanProperty())

有了这个委托(delegate),Byte Buddy 首先调用 intercepor(然后丢弃任何潜在的返回值),最后应用作为参数传递给 andThen 方法的 Instrumentation .

关于Java 字节码 : Customized setter/getter with byte buddy,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26627981/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com