当前位置: 首页 > 知识库问答 >
问题:

如何在现有类中定义新方法,并使用bytebuddy在同一类中的现有方法中添加对该方法的调用?

柴正祥
2023-03-14

我有一个如下所示的课程

public class HelloWorld{
  public void sayHelloWorld(){
    System.out.println("Hello World");
  }
}

现在,我想使用bytebuddy向HelloWorld类添加另一个方法,并在sayHelloWorld中添加对新方法的调用。所以假设在比特巴迪表演了魔法之后,这个班级会变成这样。(我知道bytebuddy使用字节码,而不是java源文件。下面的代码只是为了说明。)

public class HelloWorld{
  public void sayHelloWorld(){
    System.out.println("Hello World");
    sayHelloAgain()
  }
  public void sayHelloAgain(){
    System.out.println("Hello Again")
  }
}
  1. 首先,bytebuddy有可能做到这一点吗
  2. 第二,如果可能的话,我该怎么做?我知道bytebuddy可以用来重新定义方法,但不能修改方法体。这是真的吗

如果有人能解释一下,那就太好了。蒂娅!

共有1个答案

钱锦
2023-03-14

Byte Buddy允许您以各种方式执行此操作。最直接的方法是定义一个拦截器,该拦截器实现sayHelloAgain,Byte Buddy将向其创建一个委托:

public class HelloAgainDelegate {
  public static void sayHelloAgain() {
    System.out.println("Hello again");
  }
}

然后,您可以在重新定义的类上定义该方法,并重新设置sayHelloWorld方法的基础,以首先调用原始方法,然后调用另一个方法:

Class<?> type = new ByteBuddy()
  .rebase(HelloWorld.class)
  .defineMethod("sayHelloAgain", void.class, Visibility.PUBLIC)
  .intercept(MethodDelegation.to(HelloAgainDelegate.class))
  .method(named("sayHelloWorld"))
  .intercept(SuperMethodCall.INSTANCE
    .andThen(MethodCall.invoke(named("sayHelloAgain"))))
  .make()
  .load(HelloWorld.class.getClassLoader(), 
        ClassLoadingStrategy.Default.CHILD_FIRST)
  .getLoaded();

Object instance = type.newInstance();
type.getMethod("sayHelloWorld").invoke(instance);
type.getMethod("sayHelloAgain").invoke(instance);

在Java代码中,重定基类的外观如下:

public class HelloWorld {
  synthetic void sayHelloWorld$origin() {
    System.out.println("Hello World");
  }  

  public void sayHelloWorld() {
    sayHelloWorld$origin();
    sayHelloAgain();
  }

  public void sayHelloAgain() {
    HelloAgainInterceptor.sayHelloAgain();
  }
}

如果此委派不是您的选项,您还可以使用Advice内联模板类中的代码:

class HelloAgainAdvice {
  @Advice.OnMethodExit
  static void sayHelloAgain() {
    System.out.println("Hello again");
  }
}

您可以通过建议使用这个类,而不是方法委派。到(HelloAgainAdvice.class)。复制代码时,您将无法设置断点,但重新定义的类将是自包含的。

 类似资料:
  • 问题内容: 我想在Route和Router类型上添加一个便捷的util方法: 但是编译器告诉我 无法在非本地类型mux.Router上定义新方法 那么我将如何实现呢?是否创建具有匿名mux.Route和mux.Router字段的新结构类型?或者是其他东西? 问题答案: 正如编译器所提到的,您不能在另一个包中扩展现有类型。您可以定义自己的别名或子包,如下所示: 或嵌入原始路由器:

  • 这是一个与实现相关的问题,或者我可能想多了。假设我有一个子类继承了父类。根据我的理解,它将继承父类的方法定义,而不是构造函数。我们需要通过超级方法调用提供或编译器将提供构造函数。我们这样做的原因是,如果没有父类对象实例,我们从子类中的父类获得的方法定义将不存在。 这是否意味着,当我调用父类对象定义的方法(该方法尚未在子类中重写)时,将在父对象实例的子类内部调用?我在想,由于子类会调用父类构造函数并

  • 代码:- 在这里,当我用mydog对象调用eat()方法时,它会打印出“dog eating”,有没有办法用mydog对象调用base Animal类的eat()方法,比如有没有像这样的东西 我不想使用super(),因为这样它也会从child类调用eat(),所以它会同时打印语句“animal eating”和“dog eating”,这是我不想要的,我想一次只调用一个语句。

  • 问题内容: 经过大量搜索,我发现有几种方法可以向现有实例对象添加绑定方法或未绑定类方法 此类方法包括以下代码采用的方法。 让我烦恼的是,输入该函数的名称,或两次。 有什么简单的方法可以将现有功能添加到类或实例中,而无需再次键入该功能的名称? 例如, 将现有功能添加到实例或类将是一种非常优雅的方法,因为该功能已经具有属性。 问题答案: 通常,当您使用点分访问查找对象字典时,存储在对象字典中的函数不会

  • 问题内容: 例: 我发现上面的代码在Java中是完全合法的。我有以下问题。 在方法内部拥有类定义的用途是什么? 是否会为生成一个类文件 我很难以面向对象的方式来想象这个概念。在行为中具有类定义。也许有人可以用等效的真实例子告诉我。 方法中的抽象类对我来说听起来有点疯狂。但不允许使用任何接口。这背后有什么原因吗? 问题答案: 这称为本地课程。 2很简单:是的,将生成一个类文件。 1和3是同一个问题。

  • 问题内容: 在Bruce Eckel的“ Thinking In Java,第四版”的第428页(有关类型信息的章节)中,具有以下示例: 也许我有点累,但是我看不到add()方法中对add()的调用是如何工作的。我一直认为它应该有一个引用,或者是一个静态方法(并且我在ArrayList或List中找不到静态add())。我想念什么? 我只是为自己测试,发现这可行: 问题答案: Java为这样的方法