【发布时间】:2013-12-06 08:52:32
【问题描述】:
我需要定义一个ClassLoader,它可以从它们各自的类文件中动态地重新加载某些类。原因是类在运行时开始后发生了变化。
目前我有一个类加载器,可以从其文件中加载一个类。我需要进一步加载这个类所依赖的所有类,并且这些类都在更改的类列表中。
简单解释,我有一个ClassLoader 类,它覆盖loadClass 方法以在所需的类在列表中时加载更改的类文件。否则,它使用默认(父)类加载器加载类。
是否也可以使用相同的类加载器从主要加载的类(重新)加载类定义中的类?
所以,一个简单的例子
Class A {
static method() {
B b = new B();
C c = new C();
// do something with B and C
}
}
Class B {
public X x = new X();
}
当我用MyCustomClassLoader 加载类A 时,我给它一个类列表,其中包含A 和C f.e.因为我知道这些类的类文件(bin/A.class)已更改。因此,它应该从类A 手动加载文件,并且在加载B 和C 时,它应该检查它们是否在更改的类列表中。当它们不是时,可以使用默认的类加载器加载它们,否则它将与 A 一样,递归地(因此还要检查 B 所依赖的类)。
我可以从文件加载,但没有递归。我也知道此方法不会全局覆盖 Java new 运算符。但我只需要运行一个更改的类,但它的依赖项也发生了变化。
编辑:
请注意,使用Instrumentation 无法实现这一点。它的文档引用了以下内容,包括retransformClasses() 和redefineClasses()。
重新转换可能会改变方法体、常量池和属性。重新转换不得添加、删除或重命名字段或方法,更改方法的签名或更改继承。这些限制可能会在未来的版本中取消。
所以我做了一个工作代理来更改方法体,但只有当我注意到它在方法创建或删除时崩溃时,我才发现了这段文字。
【问题讨论】:
-
我不确定在运行中彻底替换一个类有多可行。加载一个,当然……因为 JVM 还没有将它合并到任何东西中。但是一旦加载,就会做出假设,JITter 会根据这些假设生成代码。最大的问题是,旧类的现有实例应该如何处理?
-
嗯,不可能替换运行时类定义,这是肯定的。但我只是想在一个类加载器中重新定义类。这不会改变运行时环境中其他地方
new运算符的行为,而只会改变使用我自己的类加载器创建的该类的实例的行为。 -
它是可能的,请参阅下面的答案。但是,请参阅有关先前定义的类的现有实例的注意事项。
-
可以替换运行时方法实现(主体),但不能使用 Instrumentation 替换类或方法的定义(签名)。
标签: java class classloader