Javassist添加方法并调用

时间:2012-12-10 09:13:21

标签: java javassist

我坚持使用javassist。我已经在运行时向我的对象类添加了一个新方法。

我的对象类:

package tmp3;

public class Car {
    public Car(){}
}

我的测试班:

package tmp3;

import java.lang.reflect.Method;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;

public class TestMain {
    public static void main(String[] args) {
        try {

            CtClass ctclass = ClassPool.getDefault().get("tmp3.Car");
            CtMethod newmethod = CtNewMethod.make("public void testPrint() { System.out.println(\"test ok\"); }",ctclass);
            ctclass.addMethod(newmethod);
            ctclass.writeFile();

            for(Method me: ctclass.toClass().getDeclaredMethods()){ //test print, ok
                System.out.println(me.getName());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

但在那之后,我不知道如何调用(调用)它。我读过javassist无法调用方法。那我怎样才能调用我刚用javassist添加的方法?

我在两天内尝试过很多东西但没有成功。你能帮帮我吗?

2 个答案:

答案 0 :(得分:9)

Java类具有静态接口,这意味着,正如您可能已经知道的那样,Java在默认情况下并未设计为在运行时向类添加方法,因此它有点棘手,但并不难以实现您想要的。

您已经使用Javassist(字节码修饰符框架)来设计编译的类以添加更多代表新方法的字节码。您可以使用以下两种方案之一:

场景1:在注入之前与您的Car类一起编译的代码

在这种情况下,在编译代码时,Java编译器只知道Car接口而不进行任何注入。所以你不能直接调用注入的方法,如下所示:

 Car car = new Car();
 car.testPrint();

你必须通过@Scorpion正确评论的反思来做到这一点:

 Car car = new Car();
 Method method = car.getClass().getMethod("testPrint", new Class[]{});
 method.invoke(car,new Object[]{});

但这不是唯一的方法......

场景2:使用编译和注入的类

的代码

如果您编译了Car类,请将其注入,然后 编写针对已编译类的代码(例如,在jar文件中具有Car类)能够将您注入的方法称为任何其他常规方法。

进行以下练习:

  1. 编译您的Car班级
  2. 运行将执行注射的TestMain
  3. 在IDE中创建另一个项目并添加到该项目的类路径中,注入类 OR 的目录创建一个仅包含注入类的jar并将该jar添加到类路径
  4. 在新项目中创建一个创建新Car实例的类,请注意您现在可以毫无困难地调用testPrint方法。
  5. 你应该注意的一些事情:

    • 如果您使用注入的类覆盖原始类,则可能最终导致无效的类导致java.lang.ClassFormatError,并显示一条错误消息,指出您有一个Truncated Class文件。如果Javassist没有将所有字节码加载到内存并尝试对同一类文件进行写入和读取,则会发生这种情况,这会导致完全混乱。为避免这种情况,您可以写入其他路径,也可以确保在写入文件之前将所有字节码加载到内存中(使用toByteCode()中的CtClass)。
    • 如果您有两个类文件,一个包含注入的代码,另一个包含原始代码,请记住在类路径中只有一个

答案 1 :(得分:0)

使用java反射来调用它,使用javassist进行类修改和加载...然后使用java反射来运行它(调用...)。