好吧,所以我有一个班级
class A{
public D d = new B$0();
public void foo(){
B$0 b;
try{
b = (B$0)this.d;
}catch(ClassCastException e){
this.d = d.move(this); //actual implementation uses a CAS to make sure it's only replaced once
throw new RepeatThisMethodException();
}
//do something with b here
}
}
RepeatThisMethodException
由某些代码进一步处理。
abstract class D{
public abstract D move(Object o);
}
和
class B$0 extends D{
public static D moveThis(A a){
throw new Error();
}
public D move(Object o){
return moveThis((A)o);
}|
}
我现在创建一个新类
class B$1 extends D{
public D move(Object o){
return B$0.moveThis((A)o);
}
}
使用ByteBuddy加载它。
DynamicType.Builder builder = byteBuddy
.subclass(D.class)
.name("B$1")
;
DynamicType.Unloaded newClass = builder.make();
byte[] rawBytecode = newClass.getBytes();
byte[] finishedBytecode = MyASMVisitor.addMethods(rawBytecode);
Class b0 = Class.forName("B$0");
ClassLoadingStrategy.Default.INJECTION.load(b0.getClassLoader(),
Collections.singletonMap(newClass.getTypeDescription(), finishedBytecode));
(请注意,我使用B$0.class.getClassloader()
加载B$1
。)
move
方法MyASMVisitor
添加的字节码如下所示:
public Method move:"(Ljava/lang/Object;)LD;"
stack 1 locals 2
{
aload_1;
checkcast class A;
invokestatic Method B$0.moveThis:"(LA;)LD;";
areturn;
}
现在加载了B$1
,我重新设法B$0
s.t.它可以处理新的类。
class B$0 extends D{
public static D moveThis(A a){
if(a.d instanceof B$1) throw new RepeatThisMethodException();
if(a.d instanceof B$0) return new B$1();
throw new Error();
}
public D move(Object o){
return moveThis((A)o);
}|
}
并使用
重新加载private void redefineClass(String classname, byte[] bytecode) {
Class clazz;
try{
clazz = Class.forName(classname);
}catch(ClassNotFoundException e){
throw new RuntimeException(e);
}
ClassReloadingStrategy s = ClassReloadingStrategy.fromInstalledAgent();
s.load(clazz.getClassLoader(),
Collections.singletonMap((TypeDescription)new TypeDescription.ForLoadedType(clazz), bytecode));
}
因此B$0
重新加载B$0.class.getClassLoader()
。
现在B$1
存在且可以处理,我让A
知道它应该从现在开始使用新类。
class A{
public D d = new B$1();
public void foo(){
B$1 b;
try{
b = (B$1)this.d;
}catch(ClassCastException e){
this.d = d.move(this); //actual implementation uses a CAS to make sure it's only replaced once
throw new RepeatThisMethodException();
}
//do something with b here
}
}
使用相同的redefineClass
方法重新加载它(因此A
会重新加载A.class.getClassLoader()
)。
实际上,A
的新实例将从一开始就使用B$1
,而现有实例将调用b.move(this)
,而B$0.moveThis((A)o)
将调用this
(它无法使用B
。
目前这似乎有效。
现在的问题是我们需要更新所有使用G
版本的类,显然,我们不能同时重新加载它们,所以有些会更早,有些会迟到。 / p>
我们假设我们有一个使用A a
的班级a.d
,因此使用A
。
G
已经重新加载,A
还没有。因此A
(或move
的任何其他已重新加载的客户端)上的某些方法可能已触发G
,B$0
仍在尝试转换为G
。
没关系。
如果A a
使用a.d
并且无法将a.d.move(a)
投射到其预期的版本,则会调用B$0.moveThis((A)a)
,然后调用if(a.d instanceof B$1) throw new RepeatThisMethodException();
。
在那种情况下,
B$0
我们在G
中处理代码中的可确保B$1
在重新加载字节码并且知道B$1
之前无法取得进展。
或 WOULD ,如果B$0.moveThis
可以致电Exception in thread "MyT1" java.lang.NoClassDefFoundError: A
at B$1.move(Unknown Source)
。
相反,我们得到了
Object o
好吧,这很不幸。让我们看看我们是否可以通过将B$0.moveThis
转换为Exception in thread "MyT1" java.lang.NoClassDefFoundError: B$0
at B$1.move(Unknown Source)
来摆脱此错误...
B$1
不,看起来不像。
如何加载B$0
s.t.它至少可以访问B$0
,A
和A
(以及最终D :> B :> C
的任何客户)都可以访问它吗?
注意
任何类型的解决方案都需要支持向上转播。
E.g。说我有B b = new C()
我们使用C
(或将B
的实例传递给期望b.move(b)
或...)的方法,然后C$0.moveThis((C)b)
必须仍然致电 Class b0 = Class.forName("B$0");
ClassLoadingStrategy.Default.INJECTION.load(b0.getClassLoader(),
Collections.singletonMap(newClass.getTypeDescription(), finishedBytecode));
try {
Class c = Class.forName("B$1");
Object instance = c.newInstance();
c.getMethod("move", Object.class).invoke(instance, new Object());
} catch (Exception e) {
e.printStackTrace();
}
。
更新(谢谢,Holger)
这些问题似乎与重新定义现有类无关。
B$1.move()
在重新加载任何其他类之前调用NoClassDefFoundError
的实际上足以触发clazz.getClassLoader()
。
更新
当我打印b0.getClassLoader()
用于重新加载类而sun.misc.Launcher$AppClassLoader
用于新类时,我总是得到<section class="s_features">
<center>
<h4 style="padding-top: 1%;padding-bottom: 1%;font-family:timesnewroman;">PRODUCTS</h4>
</center>
<div class="container hidden-xs" id="moto" style="">
<div class="container">
<div class="row">
<div class="col-md-2">
<a id="bgc" href="/shop/category/light-bulb-4" class="btn btn-default">
<img class="img img-responsive padding-xl" src="/web/image/426/2543.png" alt="Odoo image and text block" data-original-title="" title="" style="">
<span style="font-family:timesnewroman;">BULB</span>
</a>
<br>
</div>
<div class="col-md-2">
<a id="bgc5" href="/shop/category/light-tube-light-9" class="btn btn-default">
<img class="img img-responsive center-block padding-large" src="/web/image/707/png.png" alt="Odoo image and text block" data-original-title="" title="" style="">
<span style="font-family:timesnewroman;">TUBE LIGHT</span>
</a>
<br>
</div>
</div>
</div></div></section>
<div class="col-md-9" id="products_grid">
<table id="tabdiv">
---here the product images are displayed when I click 'a' tag
</table>
</div>
的相同实例。