在运行时替换(覆盖)类实现(Java)

时间:2009-11-05 18:53:27

标签: java runtime classloader

有没有办法替换(覆盖)一个Java类实现,它已经由另一个实现的System类加载器加载(可用作字节数组)?

为了说明我的疑问,请遵循以下代码:

public class Main {
    public static void main(String ... args) {
        Foo foo = new Foo();
        foo.print();

        ClassLoader cl = ...

        Foo foo2 = (Foo) cl.newInstance();
        foo2.print();
    }
}

第一个Foo的print()方法打印“Implementation 1”,第二个打印“Implementation 2”。 foo的第二个实例由类加载器从一个字节数组中检索(可以存储在一个文件中,或从任何流中获取......)

PS:要求Foo是一个类,而不是一个接口,并且不能扩展,即定义类实现的实际字节(在VM内部)被覆盖。

4 个答案:

答案 0 :(得分:4)

是的,这没问题。您应该使用java.net.URLClassLoader。例如,您可以为其指定一个网址,该网址是您的覆盖Foo.class文件所在的目录。

编辑: 然后你想要的电话是cl.loadClass("Foo").newInstance()。您无法将结果转换为Foo,但您可以使用反射来调用其print方法。或者让Foo成为你不会重新实现的东西的子类(或接口实现),它定义了一个print方法,然后强制转换为它。

答案 1 :(得分:0)

CGLib做这样的事情。它用于Spring& Hibernate用于此目的。

答案 2 :(得分:0)

您可以实现一个检测代理,并使用java.lang.instrument.Instrumentation#redefineClasses(...)替换已加载类的字节码。

答案 3 :(得分:0)

我使用JMX取消部署和重新部署类。