在运行时替换(覆盖)类实现 (Java)
是否有任何方法可以替换(覆盖)已由系统类加载器加载的另一个实现(以字节数组形式提供)的 Java 类实现?
为了说明我的疑问,请遵循以下代码:
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”,而第二个 Foo 则打印“Implementation 2”。 foo 的第二个实例由类加载器从字节数组中检索(可以存储在文件中,或从任何流中获取...)
PS:要求 Foo 是一个类,而不是一个接口,并且无法扩展,即定义类实现的实际字节(VM 内部)被覆盖。
Is there any way of substituting (overriding) a Java class implementation, which is already loaded by the System class loader by another implementation (available as an array of bytes)?
To illustrate my doubt, follows this code:
public class Main {
public static void main(String ... args) {
Foo foo = new Foo();
foo.print();
ClassLoader cl = ...
Foo foo2 = (Foo) cl.newInstance();
foo2.print();
}
}
The print() method of the first Foo prints "Implementation 1", as the second one prints "Implementation 2". The second instance of foo is retrieved by the class loader from an array of bytes (which can be stored in a file, or got from any stream...)
PS: Is a requirement that Foo is a class, not an interface, and cannot be extended, i.e., the actual bytes (inside the VM) that defines the class implementation are overrided.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
是的,这没问题。您应该使用
java.net.URLClassLoader
。例如,您可以给它一个 url,它是您的覆盖Foo.class
文件所在的目录。编辑:
那么你想要的调用是
cl.loadClass("Foo").newInstance()
。您无法将结果强制转换为Foo
,但可以使用反射来调用其print
方法。或者使 Foo 成为您不会重新实现的子类(或接口实现),该子类定义了print
方法,并强制转换为该方法。Yes, this is no problem. You should use a
java.net.URLClassLoader
. For example, you could give it a url which is a directory where your overridingFoo.class
file lives.Edit:
Then the call you want is
cl.loadClass("Foo").newInstance()
. You can't cast the result to aFoo
, but you can use reflection to call itsprint
method. Or make Foo a subclass (or interface implementation) of something you won't be reimplementing which defines aprint
method, and cast to that.CGLib 就是这样做的。它用于 Spring 和 Spring 中。休眠就是为了这个目的。
CGLib does things like this. It is used in Spring & Hibernate for this purpose.
您可以实现一个检测代理并使用 java.lang.instrument.Instrumentation#redefineClasses(...) 来替换已加载类的字节码。
You can implement an instrumentation agent and use java.lang.instrument.Instrumentation#redefineClasses(...) to replace the bytecode of already loaded classes.
我使用 JMX 取消部署和重新部署类。
I use JMX to undeploy and the redeploy classes.