We currently use premain to transform all classes before they have been loaded. But we want to make the transformation under control, Which means we can remove/re-add the code we inserted at the methods.
So we found the retransform, but i am not quite understand it.
UPDATED
For example, we have class A. Class A has two method foo() and bar():
void foo() {
while(true) {
bar();
}
}
void bar() {
System.out.println("a");
}
we call Instrument.retransformClasses(A.class). and change bar() to:
void bar() {
System.out.println("b");
}
If there is a thread already invoking foo(), can we have the output:
...
a
a
a
b
b
b
...
if not, is there any way to implement it?
So you already have a ClassFileTransformer
to transform a class' bytecode before it is loaded and installed in the JVM. And now you would want to re-transform again along the JVM lifecycle, isn't it?
Well, retransformation can be done through Instrumentation, through the Instrumentation.retransformClasses method. But first, you have to ensure that retransformation is supported by calling Instrumentation.isRetransformClassesSupported.
When will this retransformation have effect? According to the javadocs:
If a retransformed method has active stack frames, those active frames continue to run the bytecodes of the original method. The retransformed method will be used on new invokes.
That means that, in your example, foo()
invokes bar()
repeatedly. If meanwhile bar
is retransformed, the transformed code will have effect the very next iteration which calls bar
.
I will add some more complexity to your example:
void foo() {
while(true) {
bar();
}
}
void bar() {
myRetransform();
System.out.println("a");
}
void myRetransform() {
// This is where a retransformation of class A, method bar, is triggered.
}
When the retransformation is triggered, the current stack frame is:
There is an active call stack frame with bar
into it, so when myRetransform
returns it will still print an "a" in the system.out.
Then, bar
will return and leave the current stack frame like this:
And now is when the last triggered transformation will take effect. I.e: in the very next invocation to bar
.