有没有办法替换(覆盖)一个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内部)被覆盖。
答案 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取消部署和重新部署类。